├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitlab-ci.yml ├── LICENSE ├── README.md ├── poetry.lock ├── pyproject.toml ├── tests ├── __init__.py └── test_wanda.py └── wanda ├── __init__.py ├── __pycache__ ├── __init__.cpython-310.pyc └── wanda.cpython-310.pyc ├── sources ├── __init__.py ├── earthview_ids.py ├── extractor.py └── generator │ ├── __init__.py │ ├── gradient1.py │ ├── gradient2.py │ ├── honeycomb.py │ ├── scheme.py │ └── tiles.py ├── utils ├── __init__.py ├── common_utils.py ├── image_utils.py └── os_utils.py └── wanda.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Workflow for Codecov 2 | on: [push] 3 | jobs: 4 | run: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, macos-latest, windows-latest] 9 | env: 10 | OS: ${{ matrix.os }} 11 | PYTHON: '3.7' 12 | steps: 13 | - uses: actions/checkout@master 14 | - name: Setup Python 15 | uses: actions/setup-python@master 16 | with: 17 | python-version: 3.7 18 | - name: Generate coverage report 19 | run: | 20 | pip install pytest 21 | pip install pytest-cov 22 | pytest --cov=./ --cov-report=xml 23 | - name: Upload coverage to Codecov 24 | uses: codecov/codecov-action@v3 25 | with: 26 | token: ${{ secrets.CODECOV_TOKEN }} 27 | directory: ./coverage/reports/ 28 | env_vars: OS,PYTHON 29 | fail_ci_if_error: true 30 | flags: unittests 31 | name: codecov-umbrella 32 | path_to_write_report: ./coverage/codecov_report.txt 33 | verbose: true 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .idea 3 | .coverage 4 | codecov 5 | coverage.xml -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: python:3.10 2 | 3 | stages: 4 | - test 5 | - lint 6 | - types 7 | - build 8 | 9 | before_script: 10 | - pip install poetry 11 | - poetry config virtualenvs.create false 12 | - poetry install 13 | 14 | Unit Tests: 15 | stage: test 16 | rules: 17 | - changes: 18 | - wanda/__init__.py 19 | when: always 20 | allow_failure: true 21 | script: 22 | - pytest -n 15 --reruns 2 --reruns-delay 3 --cov=./ --cov-report=xml 23 | - apt install curl 24 | - curl -Os https://uploader.codecov.io/latest/linux/codecov 25 | - chmod +x codecov 26 | - ./codecov -t ${CODECOV_TOKEN} 27 | 28 | Python Code Lint: 29 | stage: lint 30 | script: 31 | - poetry run black . 32 | 33 | Static Type check: 34 | stage: types 35 | script: 36 | - poetry run mypy . 37 | 38 | Build: 39 | stage: build 40 | script: 41 | - poetry build 42 | artifacts: 43 | paths: 44 | - dist/*.* 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kshitij B 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wanda 2 | Set random wallpapers with or without a keyword 3 | 4 | [![PyPI](https://img.shields.io/pypi/v/wanda)](https://pypi.org/project/wanda/) 5 | [![PyPI - Downloads](https://img.shields.io/pypi/dm/wanda)](https://pypistats.org/packages/wanda) 6 | [![PyPI - License](https://img.shields.io/pypi/l/wanda)](https://tldrlegal.com/license/mit-license) 7 | 8 | ## Installation / Update 9 | ### On Windows/Linux: 10 | ``` 11 | pip install wanda -U 12 | ``` 13 | You may also use [pipx](https://pipx.pypa.io/latest/) 14 | 15 | ### On android:
16 | Install [termux](https://github.com/termux/termux-app) and [termux-api](https://github.com/termux/termux-api) 17 | In termux:
18 | ``` 19 | pkg up 20 | pkg in clang pkg-config libxml2 libxslt libjpeg-turbo termux-api python 21 | pip install cython lxml==5.2.2 22 | pip install wanda -U 23 | ``` 24 | 25 | For issues installing pillow refer this [document](https://pillow.readthedocs.io/en/stable/installation.html) 26 | 27 | 28 | ## Usage 29 | ``` 30 | # Set randomly (uses picsum) 31 | wanda 32 | 33 | # Set from a keyword (uses picsum) 34 | wanda -t mountain 35 | 36 | # Set from a source 37 | wanda -s wallhaven 38 | 39 | # Set from a source with keyword 40 | wanda -s wallhaven -t japan 41 | 42 | # Use shortcode for source (w=wallhaven) 43 | # For other shortcodes for other sources, check 'wanda -u' 44 | wanda -s w -t japan 45 | 46 | # Set album covers (m=musicbrainz) 47 | # album cover would be square, so use -f to fit it to screen 48 | # format for query with musicbrainz is 'artist-album' 49 | wanda -s m -t "Meltt-Love Again" -f 50 | 51 | # Set from folder (l=local) 52 | wanda -s l -t "/path/to/wallpapers" 53 | 54 | # download current wallpaper 55 | wanda -d 56 | 57 | # android specific - set wallpaper to lockscreen only 58 | wanda -l 59 | 60 | # android specific - set wallpaper to homescreen only 61 | wanda -o 62 | 63 | ``` 64 | `wanda -h` for more details 65 | 66 | ## Notes 67 | 68 | - By default, the source is [picsum](https://picsum.photos). 69 | - Some sources may have inapt images. Use them at your own risk. 70 | 71 | ## Supported sources 72 | 73 | - [4chan](https://boards.4chan.org) via [Rozen Arcana](https://archive-media.palanq.win) 74 | - [artstation](https://artstation.com) 75 | - [imgur](https://imgur.com) via [rimgo](https://rimgo.projectsegfau.lt) 76 | - [earthview](https://chromewebstore.google.com/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh) 77 | - generated 78 | - local 79 | - [musicbrainz](https://musicbrainz.org/) (Album covers) 80 | - [picsum](https://picsum.photos) 81 | - [reddit](https://reddit.com) 82 | - [wallhaven](https://wallhaven.cc) 83 | - [waifu](https://www.waifu.im/) 84 | 85 | ## Build 86 | [python](https://www.python.org/downloads) and [poetry](https://python-poetry.org) are needed 87 | ``` 88 | git clone https://github.com/ksh-b/wanda.git 89 | cd wanda 90 | poetry install 91 | poetry build 92 | poetry run wanda 93 | ``` 94 | 95 | ## Uninstall 96 | ``` 97 | pip uninstall wanda 98 | ``` 99 | 100 | ## Why the name 'wanda' 101 | This project was originally called [Wallpapers-ANDroid](https://github.com/ksyko/wallpaper-android) 102 |
103 | 104 | Why the a at the end? 'wand' was already taken I think. a for awesome, i guess. 105 |
106 | 107 | 108 | ## License 109 | MIT 110 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "appdirs" 5 | version = "1.4.4" 6 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 7 | optional = false 8 | python-versions = "*" 9 | groups = ["main"] 10 | files = [ 11 | { file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" }, 12 | { file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41" }, 13 | ] 14 | 15 | [[package]] 16 | name = "certifi" 17 | version = "2025.1.31" 18 | description = "Python package for providing Mozilla's CA Bundle." 19 | optional = false 20 | python-versions = ">=3.6" 21 | groups = ["main"] 22 | files = [ 23 | { file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" }, 24 | { file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651" }, 25 | ] 26 | 27 | [[package]] 28 | name = "charset-normalizer" 29 | version = "3.4.1" 30 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 31 | optional = false 32 | python-versions = ">=3.7" 33 | groups = ["main"] 34 | files = [ 35 | { file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de" }, 36 | { file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176" }, 37 | { file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037" }, 38 | { file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f" }, 39 | { file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a" }, 40 | { file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a" }, 41 | { file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247" }, 42 | { file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408" }, 43 | { file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb" }, 44 | { file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d" }, 45 | { file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807" }, 46 | { file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f" }, 47 | { file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f" }, 48 | { file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125" }, 49 | { file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1" }, 50 | { file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3" }, 51 | { file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd" }, 52 | { file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00" }, 53 | { file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12" }, 54 | { file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77" }, 55 | { file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146" }, 56 | { file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd" }, 57 | { file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6" }, 58 | { file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8" }, 59 | { file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b" }, 60 | { file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76" }, 61 | { file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545" }, 62 | { file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7" }, 63 | { file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757" }, 64 | { file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa" }, 65 | { file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d" }, 66 | { file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" }, 67 | { file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b" }, 68 | { file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d" }, 69 | { file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a" }, 70 | { file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9" }, 71 | { file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1" }, 72 | { file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35" }, 73 | { file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f" }, 74 | { file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda" }, 75 | { file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313" }, 76 | { file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9" }, 77 | { file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b" }, 78 | { file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11" }, 79 | { file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f" }, 80 | { file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd" }, 81 | { file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2" }, 82 | { file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886" }, 83 | { file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601" }, 84 | { file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd" }, 85 | { file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407" }, 86 | { file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971" }, 87 | { file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089" }, 88 | { file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d" }, 89 | { file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf" }, 90 | { file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e" }, 91 | { file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a" }, 92 | { file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd" }, 93 | { file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534" }, 94 | { file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e" }, 95 | { file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e" }, 96 | { file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa" }, 97 | { file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487" }, 98 | { file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d" }, 99 | { file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c" }, 100 | { file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9" }, 101 | { file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8" }, 102 | { file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6" }, 103 | { file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c" }, 104 | { file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a" }, 105 | { file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd" }, 106 | { file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd" }, 107 | { file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824" }, 108 | { file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca" }, 109 | { file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b" }, 110 | { file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e" }, 111 | { file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4" }, 112 | { file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41" }, 113 | { file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f" }, 114 | { file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2" }, 115 | { file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770" }, 116 | { file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4" }, 117 | { file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537" }, 118 | { file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496" }, 119 | { file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78" }, 120 | { file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7" }, 121 | { file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6" }, 122 | { file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294" }, 123 | { file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5" }, 124 | { file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765" }, 125 | { file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85" }, 126 | { file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3" }, 127 | ] 128 | 129 | [[package]] 130 | name = "cloudscraper" 131 | version = "1.2.71" 132 | description = "A Python module to bypass Cloudflare's anti-bot page." 133 | optional = false 134 | python-versions = "*" 135 | groups = ["main"] 136 | files = [ 137 | { file = "cloudscraper-1.2.71-py2.py3-none-any.whl", hash = "sha256:76f50ca529ed2279e220837befdec892626f9511708e200d48d5bb76ded679b0" }, 138 | { file = "cloudscraper-1.2.71.tar.gz", hash = "sha256:429c6e8aa6916d5bad5c8a5eac50f3ea53c9ac22616f6cb21b18dcc71517d0d3" }, 139 | ] 140 | 141 | [package.dependencies] 142 | pyparsing = ">=2.4.7" 143 | requests = ">=2.9.2" 144 | requests-toolbelt = ">=0.9.1" 145 | 146 | [[package]] 147 | name = "colorthief" 148 | version = "0.2.1" 149 | description = "A module for grabbing the color palette from an image." 150 | optional = false 151 | python-versions = "*" 152 | groups = ["main"] 153 | files = [ 154 | { file = "colorthief-0.2.1-py2.py3-none-any.whl", hash = "sha256:b04fc8ce5cf9c888768745e29cb19b7b688d5711af6fba26e8057debabec56b9" }, 155 | { file = "colorthief-0.2.1.tar.gz", hash = "sha256:079cb0c95bdd669c4643e2f7494de13b0b6029d5cdbe2d74d5d3c3386bd57221" }, 156 | ] 157 | 158 | [package.dependencies] 159 | Pillow = "*" 160 | 161 | [[package]] 162 | name = "cython" 163 | version = "3.0.12" 164 | description = "The Cython compiler for writing C extensions in the Python language." 165 | optional = false 166 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 167 | groups = ["main"] 168 | markers = "sys_platform == \"darwin\"" 169 | files = [ 170 | { file = "Cython-3.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba67eee9413b66dd9fbacd33f0bc2e028a2a120991d77b5fd4b19d0b1e4039b9" }, 171 | { file = "Cython-3.0.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee2717e5b5f7d966d0c6e27d2efe3698c357aa4d61bb3201997c7a4f9fe485a" }, 172 | { file = "Cython-3.0.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cffc3464f641c8d0dda942c7c53015291beea11ec4d32421bed2f13b386b819" }, 173 | { file = "Cython-3.0.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d3a8f81980ffbd74e52f9186d8f1654e347d0c44bfea6b5997028977f481a179" }, 174 | { file = "Cython-3.0.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8d32856716c369d01f2385ad9177cdd1a11079ac89ea0932dc4882de1aa19174" }, 175 | { file = "Cython-3.0.12-cp310-cp310-win32.whl", hash = "sha256:712c3f31adec140dc60d064a7f84741f50e2c25a8edd7ae746d5eb4d3ef7072a" }, 176 | { file = "Cython-3.0.12-cp310-cp310-win_amd64.whl", hash = "sha256:d6945694c5b9170cfbd5f2c0d00ef7487a2de7aba83713a64ee4ebce7fad9e05" }, 177 | { file = "Cython-3.0.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feb86122a823937cc06e4c029d80ff69f082ebb0b959ab52a5af6cdd271c5dc3" }, 178 | { file = "Cython-3.0.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfdbea486e702c328338314adb8e80f5f9741f06a0ae83aaec7463bc166d12e8" }, 179 | { file = "Cython-3.0.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563de1728c8e48869d2380a1b76bbc1b1b1d01aba948480d68c1d05e52d20c92" }, 180 | { file = "Cython-3.0.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398d4576c1e1f6316282aa0b4a55139254fbed965cba7813e6d9900d3092b128" }, 181 | { file = "Cython-3.0.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1e5eadef80143026944ea8f9904715a008f5108d1d644a89f63094cc37351e73" }, 182 | { file = "Cython-3.0.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a93cbda00a5451175b97dea5a9440a3fcee9e54b4cba7a7dbcba9a764b22aec" }, 183 | { file = "Cython-3.0.12-cp311-cp311-win32.whl", hash = "sha256:3109e1d44425a2639e9a677b66cd7711721a5b606b65867cb2d8ef7a97e2237b" }, 184 | { file = "Cython-3.0.12-cp311-cp311-win_amd64.whl", hash = "sha256:d4b70fc339adba1e2111b074ee6119fe9fd6072c957d8597bce9a0dd1c3c6784" }, 185 | { file = "Cython-3.0.12-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe030d4a00afb2844f5f70896b7f2a1a0d7da09bf3aa3d884cbe5f73fff5d310" }, 186 | { file = "Cython-3.0.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7fec4f052b8fe173fe70eae75091389955b9a23d5cec3d576d21c5913b49d47" }, 187 | { file = "Cython-3.0.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0faa5e39e5c8cdf6f9c3b1c3f24972826e45911e7f5b99cf99453fca5432f45e" }, 188 | { file = "Cython-3.0.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d53de996ed340e9ab0fc85a88aaa8932f2591a2746e1ab1c06e262bd4ec4be7" }, 189 | { file = "Cython-3.0.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea3a0e19ab77266c738aa110684a753a04da4e709472cadeff487133354d6ab8" }, 190 | { file = "Cython-3.0.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c151082884be468f2f405645858a857298ac7f7592729e5b54788b5c572717ba" }, 191 | { file = "Cython-3.0.12-cp312-cp312-win32.whl", hash = "sha256:3083465749911ac3b2ce001b6bf17f404ac9dd35d8b08469d19dc7e717f5877a" }, 192 | { file = "Cython-3.0.12-cp312-cp312-win_amd64.whl", hash = "sha256:c0b91c7ebace030dd558ea28730de8c580680b50768e5af66db2904a3716c3e3" }, 193 | { file = "Cython-3.0.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4ee6f1ea1bead8e6cbc4e64571505b5d8dbdb3b58e679d31f3a84160cebf1a1a" }, 194 | { file = "Cython-3.0.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57aefa6d3341109e46ec1a13e3a763aaa2cbeb14e82af2485b318194be1d9170" }, 195 | { file = "Cython-3.0.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:879ae9023958d63c0675015369384642d0afb9c9d1f3473df9186c42f7a9d265" }, 196 | { file = "Cython-3.0.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36fcd584dae547de6f095500a380f4a0cce72b7a7e409e9ff03cb9beed6ac7a1" }, 197 | { file = "Cython-3.0.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62b79dcc0de49efe9e84b9d0e2ae0a6fc9b14691a65565da727aa2e2e63c6a28" }, 198 | { file = "Cython-3.0.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4aa255781b093a8401109d8f2104bbb2e52de7639d5896aefafddc85c30e0894" }, 199 | { file = "Cython-3.0.12-cp313-cp313-win32.whl", hash = "sha256:77d48f2d4bab9fe1236eb753d18f03e8b2619af5b6f05d51df0532a92dfb38ab" }, 200 | { file = "Cython-3.0.12-cp313-cp313-win_amd64.whl", hash = "sha256:86c304b20bd57c727c7357e90d5ba1a2b6f1c45492de2373814d7745ef2e63b4" }, 201 | { file = "Cython-3.0.12-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ff5c0b6a65b08117d0534941d404833d516dac422eee88c6b4fd55feb409a5ed" }, 202 | { file = "Cython-3.0.12-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:680f1d6ed4436ae94805db264d6155ed076d2835d84f20dcb31a7a3ad7f8668c" }, 203 | { file = "Cython-3.0.12-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc24609613fa06d0d896309f7164ba168f7e8d71c1e490ed2a08d23351c3f41" }, 204 | { file = "Cython-3.0.12-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1879c073e2b34924ce9b7ca64c212705dcc416af4337c45f371242b2e5f6d32" }, 205 | { file = "Cython-3.0.12-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:bfb75123dd4ff767baa37d7036da0de2dfb6781ff256eef69b11b88b9a0691d1" }, 206 | { file = "Cython-3.0.12-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:f39640f8df0400cde6882e23c734f15bb8196de0a008ae5dc6c8d1ec5957d7c8" }, 207 | { file = "Cython-3.0.12-cp36-cp36m-win32.whl", hash = "sha256:8c9efe9a0895abee3cadfdad4130b30f7b5e57f6e6a51ef2a44f9fc66a913880" }, 208 | { file = "Cython-3.0.12-cp36-cp36m-win_amd64.whl", hash = "sha256:63d840f2975e44d74512f8f34f1f7cb8121c9428e26a3f6116ff273deb5e60a2" }, 209 | { file = "Cython-3.0.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:75c5acd40b97cff16fadcf6901a91586cbca5dcdba81f738efaf1f4c6bc8dccb" }, 210 | { file = "Cython-3.0.12-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e62564457851db1c40399bd95a5346b9bb99e17a819bf583b362f418d8f3457a" }, 211 | { file = "Cython-3.0.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ccd1228cc203b1f1b8a3d403f5a20ad1c40e5879b3fbf5851ce09d948982f2c" }, 212 | { file = "Cython-3.0.12-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25529ee948f44d9a165ff960c49d4903267c20b5edf2df79b45924802e4cca6e" }, 213 | { file = "Cython-3.0.12-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:90cf599372c5a22120609f7d3a963f17814799335d56dd0dcf8fe615980a8ae1" }, 214 | { file = "Cython-3.0.12-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9f8c48748a9c94ea5d59c26ab49ad0fad514d36f894985879cf3c3ca0e600bf4" }, 215 | { file = "Cython-3.0.12-cp37-cp37m-win32.whl", hash = "sha256:3e4fa855d98bc7bd6a2049e0c7dc0dcf595e2e7f571a26e808f3efd84d2db374" }, 216 | { file = "Cython-3.0.12-cp37-cp37m-win_amd64.whl", hash = "sha256:120681093772bf3600caddb296a65b352a0d3556e962b9b147efcfb8e8c9801b" }, 217 | { file = "Cython-3.0.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:731d719423e041242c9303c80cae4327467299b90ffe62d4cc407e11e9ea3160" }, 218 | { file = "Cython-3.0.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3238a29f37999e27494d120983eca90d14896b2887a0bd858a381204549137a" }, 219 | { file = "Cython-3.0.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b588c0a089a9f4dd316d2f9275230bad4a7271e5af04e1dc41d2707c816be44b" }, 220 | { file = "Cython-3.0.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab9f5198af74eb16502cc143cdde9ca1cbbf66ea2912e67440dd18a36e3b5fa" }, 221 | { file = "Cython-3.0.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8ee841c0e114efa1e849c281ac9b8df8aa189af10b4a103b1c5fd71cbb799679" }, 222 | { file = "Cython-3.0.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:43c48b5789398b228ea97499f5b864843ba9b1ab837562a9227c6f58d16ede8b" }, 223 | { file = "Cython-3.0.12-cp38-cp38-win32.whl", hash = "sha256:5e5f17c48a4f41557fbcc7ee660ccfebe4536a34c557f553b6893c1b3c83df2d" }, 224 | { file = "Cython-3.0.12-cp38-cp38-win_amd64.whl", hash = "sha256:309c081057930bb79dc9ea3061a1af5086c679c968206e9c9c2ec90ab7cb471a" }, 225 | { file = "Cython-3.0.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54115fcc126840926ff3b53cfd2152eae17b3522ae7f74888f8a41413bd32f25" }, 226 | { file = "Cython-3.0.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629db614b9c364596d7c975fa3fb3978e8c5349524353dbe11429896a783fc1e" }, 227 | { file = "Cython-3.0.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af081838b0f9e12a83ec4c3809a00a64c817f489f7c512b0e3ecaf5f90a2a816" }, 228 | { file = "Cython-3.0.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:34ce459808f7d8d5d4007bc5486fe50532529096b43957af6cbffcb4d9cc5c8d" }, 229 | { file = "Cython-3.0.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d6c6cd6a75c8393e6805d17f7126b96a894f310a1a9ea91c47d141fb9341bfa8" }, 230 | { file = "Cython-3.0.12-cp39-cp39-win32.whl", hash = "sha256:a4032e48d4734d2df68235d21920c715c451ac9de15fa14c71b378e8986b83be" }, 231 | { file = "Cython-3.0.12-cp39-cp39-win_amd64.whl", hash = "sha256:dcdc3e5d4ce0e7a4af6903ed580833015641e968d18d528d8371e2435a34132c" }, 232 | { file = "Cython-3.0.12-py2.py3-none-any.whl", hash = "sha256:0038c9bae46c459669390e53a1ec115f8096b2e4647ae007ff1bf4e6dee92806" }, 233 | { file = "cython-3.0.12.tar.gz", hash = "sha256:b988bb297ce76c671e28c97d017b95411010f7c77fa6623dd0bb47eed1aee1bc" }, 234 | ] 235 | 236 | [[package]] 237 | name = "filetype" 238 | version = "1.2.0" 239 | description = "Infer file type and MIME type of any file/buffer. No external dependencies." 240 | optional = false 241 | python-versions = "*" 242 | groups = ["main"] 243 | files = [ 244 | { file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25" }, 245 | { file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb" }, 246 | ] 247 | 248 | [[package]] 249 | name = "idna" 250 | version = "3.10" 251 | description = "Internationalized Domain Names in Applications (IDNA)" 252 | optional = false 253 | python-versions = ">=3.6" 254 | groups = ["main"] 255 | files = [ 256 | { file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" }, 257 | { file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9" }, 258 | ] 259 | 260 | [package.extras] 261 | all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] 262 | 263 | [[package]] 264 | name = "lxml" 265 | version = "5.3.1" 266 | description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." 267 | optional = false 268 | python-versions = ">=3.6" 269 | groups = ["main"] 270 | files = [ 271 | { file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b" }, 272 | { file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b" }, 273 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5" }, 274 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3" }, 275 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c" }, 276 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2" }, 277 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac" }, 278 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9" }, 279 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9" }, 280 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79" }, 281 | { file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2" }, 282 | { file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51" }, 283 | { file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406" }, 284 | { file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5" }, 285 | { file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0" }, 286 | { file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23" }, 287 | { file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c" }, 288 | { file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f" }, 289 | { file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607" }, 290 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8" }, 291 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a" }, 292 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27" }, 293 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666" }, 294 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79" }, 295 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65" }, 296 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709" }, 297 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629" }, 298 | { file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33" }, 299 | { file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295" }, 300 | { file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c" }, 301 | { file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c" }, 302 | { file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff" }, 303 | { file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2" }, 304 | { file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6" }, 305 | { file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c" }, 306 | { file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe" }, 307 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9" }, 308 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a" }, 309 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0" }, 310 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7" }, 311 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae" }, 312 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519" }, 313 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322" }, 314 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468" }, 315 | { file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367" }, 316 | { file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd" }, 317 | { file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c" }, 318 | { file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f" }, 319 | { file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645" }, 320 | { file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5" }, 321 | { file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf" }, 322 | { file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e" }, 323 | { file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd" }, 324 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7" }, 325 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414" }, 326 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e" }, 327 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1" }, 328 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5" }, 329 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423" }, 330 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20" }, 331 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8" }, 332 | { file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9" }, 333 | { file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c" }, 334 | { file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b" }, 335 | { file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5" }, 336 | { file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252" }, 337 | { file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78" }, 338 | { file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332" }, 339 | { file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81" }, 340 | { file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a" }, 341 | { file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439" }, 342 | { file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac" }, 343 | { file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d" }, 344 | { file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a" }, 345 | { file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576" }, 346 | { file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9" }, 347 | { file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32" }, 348 | { file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61" }, 349 | { file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19" }, 350 | { file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307" }, 351 | { file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70" }, 352 | { file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9" }, 353 | { file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53" }, 354 | { file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce" }, 355 | { file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407" }, 356 | { file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5" }, 357 | { file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e" }, 358 | { file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098" }, 359 | { file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5" }, 360 | { file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7" }, 361 | { file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf" }, 362 | { file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2" }, 363 | { file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb" }, 364 | { file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73" }, 365 | { file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc" }, 366 | { file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7" }, 367 | { file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f" }, 368 | { file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8" }, 369 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a" }, 370 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125" }, 371 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd" }, 372 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549" }, 373 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3" }, 374 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e" }, 375 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914" }, 376 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b" }, 377 | { file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be" }, 378 | { file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e" }, 379 | { file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675" }, 380 | { file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2" }, 381 | { file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af" }, 382 | { file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0" }, 383 | { file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2" }, 384 | { file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725" }, 385 | { file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d" }, 386 | { file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84" }, 387 | { file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2" }, 388 | { file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877" }, 389 | { file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499" }, 390 | { file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131" }, 391 | { file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3" }, 392 | { file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50" }, 393 | { file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394" }, 394 | { file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98" }, 395 | { file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314" }, 396 | { file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1" }, 397 | { file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615" }, 398 | { file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1" }, 399 | { file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de" }, 400 | { file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac" }, 401 | { file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde" }, 402 | { file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270" }, 403 | { file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca" }, 404 | { file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6" }, 405 | { file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a" }, 406 | { file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe" }, 407 | { file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2" }, 408 | { file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8" }, 409 | ] 410 | 411 | [package.extras] 412 | cssselect = ["cssselect (>=0.7)"] 413 | html-clean = ["lxml_html_clean"] 414 | html5 = ["html5lib"] 415 | htmlsoup = ["BeautifulSoup4"] 416 | source = ["Cython (>=3.0.11,<3.1.0)"] 417 | 418 | [[package]] 419 | name = "musicbrainzngs" 420 | version = "0.7.1" 421 | description = "Python bindings for the MusicBrainz NGS and the Cover Art Archive webservices" 422 | optional = false 423 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 424 | groups = ["main"] 425 | files = [ 426 | { file = "musicbrainzngs-0.7.1-py2.py3-none-any.whl", hash = "sha256:e841a8f975104c0a72290b09f59326050194081a5ae62ee512f41915090e1a10" }, 427 | { file = "musicbrainzngs-0.7.1.tar.gz", hash = "sha256:ab1c0100fd0b305852e65f2ed4113c6de12e68afd55186987b8ed97e0f98e627" }, 428 | ] 429 | 430 | [[package]] 431 | name = "pillow" 432 | version = "10.4.0" 433 | description = "Python Imaging Library (Fork)" 434 | optional = false 435 | python-versions = ">=3.8" 436 | groups = ["main"] 437 | files = [ 438 | { file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e" }, 439 | { file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d" }, 440 | { file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856" }, 441 | { file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f" }, 442 | { file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b" }, 443 | { file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc" }, 444 | { file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e" }, 445 | { file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46" }, 446 | { file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984" }, 447 | { file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141" }, 448 | { file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1" }, 449 | { file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c" }, 450 | { file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be" }, 451 | { file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3" }, 452 | { file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6" }, 453 | { file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe" }, 454 | { file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319" }, 455 | { file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d" }, 456 | { file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696" }, 457 | { file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496" }, 458 | { file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91" }, 459 | { file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22" }, 460 | { file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94" }, 461 | { file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597" }, 462 | { file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80" }, 463 | { file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca" }, 464 | { file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef" }, 465 | { file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a" }, 466 | { file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b" }, 467 | { file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9" }, 468 | { file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42" }, 469 | { file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a" }, 470 | { file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9" }, 471 | { file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3" }, 472 | { file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb" }, 473 | { file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70" }, 474 | { file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be" }, 475 | { file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0" }, 476 | { file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc" }, 477 | { file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a" }, 478 | { file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309" }, 479 | { file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060" }, 480 | { file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea" }, 481 | { file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d" }, 482 | { file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736" }, 483 | { file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b" }, 484 | { file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2" }, 485 | { file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680" }, 486 | { file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b" }, 487 | { file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd" }, 488 | { file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84" }, 489 | { file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0" }, 490 | { file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e" }, 491 | { file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab" }, 492 | { file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d" }, 493 | { file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b" }, 494 | { file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd" }, 495 | { file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126" }, 496 | { file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b" }, 497 | { file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c" }, 498 | { file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1" }, 499 | { file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df" }, 500 | { file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef" }, 501 | { file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5" }, 502 | { file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e" }, 503 | { file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4" }, 504 | { file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da" }, 505 | { file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026" }, 506 | { file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e" }, 507 | { file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5" }, 508 | { file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885" }, 509 | { file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5" }, 510 | { file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b" }, 511 | { file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908" }, 512 | { file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b" }, 513 | { file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8" }, 514 | { file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a" }, 515 | { file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27" }, 516 | { file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3" }, 517 | { file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06" }, 518 | ] 519 | 520 | [package.extras] 521 | docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] 522 | fpx = ["olefile"] 523 | mic = ["olefile"] 524 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] 525 | typing = ["typing-extensions"] 526 | xmp = ["defusedxml"] 527 | 528 | [[package]] 529 | name = "pyobjc-core" 530 | version = "11.0" 531 | description = "Python<->ObjC Interoperability Module" 532 | optional = false 533 | python-versions = ">=3.8" 534 | groups = ["main"] 535 | markers = "sys_platform == \"darwin\"" 536 | files = [ 537 | { file = "pyobjc_core-11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:10866b3a734d47caf48e456eea0d4815c2c9b21856157db5917b61dee06893a1" }, 538 | { file = "pyobjc_core-11.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:50675c0bb8696fe960a28466f9baf6943df2928a1fd85625d678fa2f428bd0bd" }, 539 | { file = "pyobjc_core-11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a03061d4955c62ddd7754224a80cdadfdf17b6b5f60df1d9169a3b1b02923f0b" }, 540 | { file = "pyobjc_core-11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c338c1deb7ab2e9436d4175d1127da2eeed4a1b564b3d83b9f3ae4844ba97e86" }, 541 | { file = "pyobjc_core-11.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b4e9dc4296110f251a4033ff3f40320b35873ea7f876bd29a1c9705bb5e08c59" }, 542 | { file = "pyobjc_core-11.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:02406ece449d0f41b31e579e47ca77ced3eb57533df955281bfcecc99da74fba" }, 543 | { file = "pyobjc_core-11.0.tar.gz", hash = "sha256:63bced211cb8a8fb5c8ff46473603da30e51112861bd02c438fbbbc8578d9a70" }, 544 | ] 545 | 546 | [[package]] 547 | name = "pyobjc-framework-cocoa" 548 | version = "10.3.2" 549 | description = "Wrappers for the Cocoa frameworks on macOS" 550 | optional = false 551 | python-versions = ">=3.8" 552 | groups = ["main"] 553 | markers = "sys_platform == \"darwin\"" 554 | files = [ 555 | { file = "pyobjc_framework_Cocoa-10.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:61f44c2adab28fdf3aa3d593c9497a2d9ceb9583ed9814adb48828c385d83ff4" }, 556 | { file = "pyobjc_framework_Cocoa-10.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7caaf8b260e81b27b7b787332846f644b9423bfc1536f6ec24edbde59ab77a87" }, 557 | { file = "pyobjc_framework_Cocoa-10.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c49e99fc4b9e613fb308651b99d52a8a9ae9916c8ef27aa2f5d585b6678a59bf" }, 558 | { file = "pyobjc_framework_Cocoa-10.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1161b5713f9b9934c12649d73a6749617172e240f9431eff9e22175262fdfda" }, 559 | { file = "pyobjc_framework_Cocoa-10.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:08e48b9ee4eb393447b2b781d16663b954bd10a26927df74f92e924c05568d89" }, 560 | { file = "pyobjc_framework_Cocoa-10.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7faa448d2038ae0e0287a326d390002e744bb6470e45995e2dbd16c892e4495a" }, 561 | { file = "pyobjc_framework_Cocoa-10.3.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:fcd53fee2be9708576617994b107aedc2c40824b648cd51e780e8399c0a447b6" }, 562 | { file = "pyobjc_framework_Cocoa-10.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:838fcf0d10674bde9ff64a3f20c0e188f2dc5e804476d80509b81c4ac1dabc59" }, 563 | { file = "pyobjc_framework_cocoa-10.3.2.tar.gz", hash = "sha256:673968e5435845bef969bfe374f31a1a6dc660c98608d2b84d5cae6eafa5c39d" }, 564 | ] 565 | 566 | [package.dependencies] 567 | pyobjc-core = ">=10.3.2" 568 | 569 | [[package]] 570 | name = "pyparsing" 571 | version = "3.1.4" 572 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 573 | optional = false 574 | python-versions = ">=3.6.8" 575 | groups = ["main"] 576 | files = [ 577 | { file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c" }, 578 | { file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032" }, 579 | ] 580 | 581 | [package.extras] 582 | diagrams = ["jinja2", "railroad-diagrams"] 583 | 584 | [[package]] 585 | name = "requests" 586 | version = "2.32.3" 587 | description = "Python HTTP for Humans." 588 | optional = false 589 | python-versions = ">=3.8" 590 | groups = ["main"] 591 | files = [ 592 | { file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" }, 593 | { file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760" }, 594 | ] 595 | 596 | [package.dependencies] 597 | certifi = ">=2017.4.17" 598 | charset-normalizer = ">=2,<4" 599 | idna = ">=2.5,<4" 600 | urllib3 = ">=1.21.1,<3" 601 | 602 | [package.extras] 603 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 604 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 605 | 606 | [[package]] 607 | name = "requests-toolbelt" 608 | version = "1.0.0" 609 | description = "A utility belt for advanced users of python-requests" 610 | optional = false 611 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 612 | groups = ["main"] 613 | files = [ 614 | { file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6" }, 615 | { file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" }, 616 | ] 617 | 618 | [package.dependencies] 619 | requests = ">=2.0.1,<3.0.0" 620 | 621 | [[package]] 622 | name = "screeninfo" 623 | version = "0.8.1" 624 | description = "Fetch location and size of physical screens." 625 | optional = false 626 | python-versions = ">=3.6.2,<4.0.0" 627 | groups = ["main"] 628 | files = [ 629 | { file = "screeninfo-0.8.1-py3-none-any.whl", hash = "sha256:e97d6b173856edcfa3bd282f81deb528188aff14b11ec3e195584e7641be733c" }, 630 | { file = "screeninfo-0.8.1.tar.gz", hash = "sha256:9983076bcc7e34402a1a9e4d7dabf3729411fd2abb3f3b4be7eba73519cd2ed1" }, 631 | ] 632 | 633 | [package.dependencies] 634 | Cython = { version = "*", markers = "sys_platform == \"darwin\"" } 635 | pyobjc-framework-Cocoa = { version = "*", markers = "sys_platform == \"darwin\"" } 636 | 637 | [[package]] 638 | name = "urllib3" 639 | version = "2.2.3" 640 | description = "HTTP library with thread-safe connection pooling, file post, and more." 641 | optional = false 642 | python-versions = ">=3.8" 643 | groups = ["main"] 644 | files = [ 645 | { file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac" }, 646 | { file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" }, 647 | ] 648 | 649 | [package.extras] 650 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] 651 | h2 = ["h2 (>=4,<5)"] 652 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 653 | zstd = ["zstandard (>=0.18.0)"] 654 | 655 | [metadata] 656 | lock-version = "2.1" 657 | python-versions = ">=3.8,<4.0.0" 658 | content-hash = "aa1f17550c78e3c8452b9d9b343eee54d72b1b1b7786c18fbf7491a954a15fdb" 659 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "wanda" 3 | version = "1.0.1" 4 | description = "Set wallpapers with keywords or randomly" 5 | authors = [{ name = "kshib", email = "ksyko@pm.me" }] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://github.com/ksh-b/wanda" 9 | repository = "https://github.com/ksh-b/wanda" 10 | keywords = ["wallpaper", "reddit", "wallhaven", "earthview", "termux"] 11 | requires-python = ">=3.8,<4.0.0" 12 | dependencies = [ 13 | "lxml (>=5.2.2,<6.0.0)", 14 | "cloudscraper (>=1.2.71,<2.0.0)", 15 | "Pillow (>=10.3.0,<11.0.0)", 16 | "screeninfo (>=0.8.1,<1.0.0)", 17 | "colorthief (>=0.2.1,<1.0.0)", 18 | "filetype (>=1.2.0,<2.0.0)", 19 | "musicbrainzngs (>=0.7.1,<1.0.0)", 20 | "appdirs (>=1.4.4,<2.0.0)" 21 | ] 22 | 23 | [project.urls] 24 | "Bug Tracker" = "https://github.com/ksh-b/wanda/issues" 25 | 26 | [poetry.group.dev.dependencies] 27 | pytest = "^8.0.0" 28 | ruff = "^0.9.6" 29 | mypy = "^1.14.1" 30 | pytest-xdist = "^3.6.1" 31 | pytest-cov = "^5.0.0" 32 | pytest-rerunfailures = "^14.0" 33 | 34 | [build-system] 35 | requires = ["poetry-core>=1.9.0"] 36 | build-backend = "poetry.core.masonry.api" 37 | 38 | [project.scripts] 39 | wanda = "wanda.wanda:run" 40 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_wanda.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import unittest 3 | from pathlib import Path 4 | 5 | import pytest 6 | 7 | import utils.common_utils as common 8 | import utils.image_utils as image 9 | from wanda.sources.extractor import * 10 | 11 | 12 | # These tests should be compatible with ci runners 13 | class SimpleTest(unittest.TestCase): 14 | good_search = "nature" 15 | bad_search = "foobarxyzzy" 16 | artstation_cdn = "https://cdn(.).artstation.com/" 17 | 18 | def assert_starts_with(self, response, url): 19 | self.assertTrue(response.startswith(url), response) 20 | 21 | def assertNotNone(self, response, url): 22 | self.assertIsNotNone(re.search(url, response), response) 23 | 24 | def test_conn_test(self): 25 | self.assertTrue(common.is_connected()) 26 | 27 | def test_local(self): 28 | self.assertRaises(SystemExit, local, None) 29 | self.assertRaises(SystemExit, local, "") 30 | 31 | def test_wallhaven(self): 32 | url = "https://w.wallhaven.cc/full/" 33 | 34 | response = wallhaven(None) 35 | self.assert_starts_with(response, url) 36 | 37 | response = wallhaven("") 38 | self.assert_starts_with(response, url) 39 | 40 | response = wallhaven(self.good_search) 41 | self.assert_starts_with(response, url) 42 | 43 | self.assertRaises(SystemExit, wallhaven, self.bad_search) 44 | 45 | def test_reddit(self): 46 | url = "https://i.redd.it/" 47 | 48 | self.assertIn("wallpaper", suggested_subreddits()) 49 | 50 | response = reddit(search=None) 51 | self.assert_starts_with(response, url) 52 | 53 | response = reddit("") 54 | self.assert_starts_with(response, url) 55 | 56 | response = reddit(self.good_search) 57 | self.assertNotNone(response, "^https?://") 58 | 59 | response = reddit("wallpaper@halflife") 60 | self.assertNotNone(response, "^https?://") 61 | 62 | self.assertRaises(SystemExit, reddit, search=self.bad_search) 63 | 64 | def test_imgur(self): 65 | url = "https://rimgo.eu.projectsegfau.lt" 66 | 67 | self.assertRaises(SystemExit, imgur, None) 68 | 69 | self.assertRaises(SystemExit, imgur, "") 70 | 71 | response = imgur(search="jmVC8") 72 | self.assert_starts_with(response, url) 73 | 74 | self.assertRaises(SystemExit, imgur, self.bad_search) 75 | 76 | def test_fourchan(self): 77 | url = "^(https?://archive-media.palanq.win/|https?://i.4cdn.org)" 78 | 79 | response = fourchan(None) 80 | self.assertNotNone(response, url) 81 | 82 | response = fourchan("") 83 | self.assertNotNone(response, url) 84 | 85 | response = fourchan("phone") 86 | self.assertNotNone(response, url) 87 | 88 | self.assertRaises(SystemExit, fourchan, self.bad_search) 89 | 90 | def test_artstation_any(self): 91 | url = self.artstation_cdn 92 | response = artstation_any(None) 93 | self.assertNotNone(response, url) 94 | 95 | response = artstation_any("") 96 | self.assertNotNone(response, url) 97 | 98 | response = artstation_any(self.good_search) 99 | self.assertNotNone(response, url) 100 | 101 | self.assertRaises(SystemExit, artstation_any, self.bad_search) 102 | 103 | def test_artstation_prints(self): 104 | url = self.artstation_cdn 105 | response = artstation_prints(None) 106 | self.assertNotNone(response, url) 107 | 108 | response = artstation_prints("") 109 | self.assertNotNone(response, url) 110 | 111 | response = artstation_prints(self.good_search) 112 | self.assertNotNone(response, url) 113 | 114 | self.assertRaises(SystemExit, artstation_prints, self.bad_search) 115 | 116 | def test_artstation_artist(self): 117 | url = self.artstation_cdn 118 | 119 | self.assertRaises(SystemExit, artstation_artist, None) 120 | self.assertRaises(SystemExit, artstation_artist, "") 121 | self.assertRaises(SystemExit, artstation_artist, self.bad_search) 122 | 123 | response = artstation_artist("tohad") 124 | self.assertNotNone(response, url) 125 | 126 | def test_earthview(self): 127 | response = earthview(None) 128 | self.assertIsNotNone(response) 129 | 130 | def test_musicbrainz(self): 131 | self.assertNotIsInstance(musicbrainz, str, "NoArtistFoo-NoAlbumBar") 132 | 133 | musicbrainz("Coldplay-Parachutes") 134 | 135 | def test_waifuim(self): 136 | url = "https://cdn.waifu.im/" 137 | 138 | response = waifuim(None) 139 | self.assert_starts_with(response, url) 140 | 141 | response = waifuim("") 142 | self.assert_starts_with(response, url) 143 | 144 | response = waifuim("uniform") 145 | self.assert_starts_with(response, url) 146 | 147 | self.assertRaises(SystemExit, waifuim, self.bad_search) 148 | 149 | 150 | # These tests would need actual device 151 | @pytest.mark.skip 152 | class AdvancedTest(unittest.TestCase): 153 | good_search = "nature" 154 | 155 | def test_size(self): 156 | self.assertEqual(type(size()), tuple) 157 | 158 | def test_set_local(self): 159 | folder = f"{str(Path.home())}/wanda" 160 | path = get_dl_path() 161 | path = common.download(path, "https://i.imgur.com/bBNy18H.jpeg") 162 | self.assertTrue(os.path.exists(path)) 163 | image.set_wp(local(folder), True, True) 164 | 165 | def test_set_wallhaven(self): 166 | image.set_wp(wallhaven(self.good_search), True, True) 167 | 168 | def test_set_artstation(self): 169 | image.set_wp(artstation_artist("tohad"), True, True) 170 | 171 | image.set_wp(artstation_prints(self.good_search), True, True) 172 | 173 | image.set_wp(artstation_any(self.good_search), True, True) 174 | 175 | def test_set_reddit(self): 176 | image.set_wp(reddit(self.good_search), True, True) 177 | 178 | image.set_wp(reddit("wallpaper@halflife"), True, True) 179 | 180 | @staticmethod 181 | def test_set_earthview(): 182 | image.set_wp(earthview(""), True, True) 183 | 184 | @staticmethod 185 | def test_set_waifuim(): 186 | image.set_wp(waifuim("uniform"), True, True) 187 | 188 | @staticmethod 189 | def test_set_fourchan(): 190 | image.set_wp(fourchan("mobile"), True, True) 191 | 192 | 193 | if __name__ == "__main__": 194 | unittest.main() 195 | -------------------------------------------------------------------------------- /wanda/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /wanda/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/wanda/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /wanda/__pycache__/wanda.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/wanda/__pycache__/wanda.cpython-310.pyc -------------------------------------------------------------------------------- /wanda/sources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/wanda/sources/__init__.py -------------------------------------------------------------------------------- /wanda/sources/earthview_ids.py: -------------------------------------------------------------------------------- 1 | earthview_ids = [ 2 | "1003", 3 | "1004", 4 | "1006", 5 | "1007", 6 | "1008", 7 | "1010", 8 | "1012", 9 | "1014", 10 | "1017", 11 | "1018", 12 | "1019", 13 | "1021", 14 | "1022", 15 | "1023", 16 | "1024", 17 | "1026", 18 | "1027", 19 | "1032", 20 | "1033", 21 | "1034", 22 | "1035", 23 | "1036", 24 | "1037", 25 | "1038", 26 | "1039", 27 | "1040", 28 | "1041", 29 | "1046", 30 | "1047", 31 | "1048", 32 | "1049", 33 | "1050", 34 | "1052", 35 | "1053", 36 | "1054", 37 | "1055", 38 | "1056", 39 | "1057", 40 | "1063", 41 | "1064", 42 | "1065", 43 | "1066", 44 | "1067", 45 | "1068", 46 | "1069", 47 | "1070", 48 | "1071", 49 | "1074", 50 | "1075", 51 | "1077", 52 | "1078", 53 | "1080", 54 | "1081", 55 | "1082", 56 | "1084", 57 | "1085", 58 | "1086", 59 | "1087", 60 | "1089", 61 | "1091", 62 | "1092", 63 | "1093", 64 | "1094", 65 | "1095", 66 | "1096", 67 | "1097", 68 | "1098", 69 | "1099", 70 | "1101", 71 | "1102", 72 | "1103", 73 | "1104", 74 | "1105", 75 | "1107", 76 | "1109", 77 | "1110", 78 | "1114", 79 | "1115", 80 | "1116", 81 | "1118", 82 | "1119", 83 | "1121", 84 | "1122", 85 | "1123", 86 | "1125", 87 | "1127", 88 | "1128", 89 | "1131", 90 | "1132", 91 | "1133", 92 | "1134", 93 | "1135", 94 | "1138", 95 | "1139", 96 | "1140", 97 | "1141", 98 | "1143", 99 | "1147", 100 | "1148", 101 | "1151", 102 | "1152", 103 | "1154", 104 | "1155", 105 | "1156", 106 | "1157", 107 | "1158", 108 | "1159", 109 | "1160", 110 | "1161", 111 | "1163", 112 | "1164", 113 | "1165", 114 | "1166", 115 | "1167", 116 | "1168", 117 | "1169", 118 | "1170", 119 | "1172", 120 | "1173", 121 | "1174", 122 | "1176", 123 | "1177", 124 | "1178", 125 | "1180", 126 | "1181", 127 | "1183", 128 | "1184", 129 | "1186", 130 | "1190", 131 | "1191", 132 | "1192", 133 | "1195", 134 | "1196", 135 | "1197", 136 | "1198", 137 | "1199", 138 | "1206", 139 | "1207", 140 | "1209", 141 | "1211", 142 | "1212", 143 | "1215", 144 | "1216", 145 | "1217", 146 | "1221", 147 | "1222", 148 | "1224", 149 | "1225", 150 | "1226", 151 | "1229", 152 | "1230", 153 | "1231", 154 | "1233", 155 | "1237", 156 | "1238", 157 | "1239", 158 | "1240", 159 | "1241", 160 | "1242", 161 | "1243", 162 | "1245", 163 | "1247", 164 | "1248", 165 | "1251", 166 | "1253", 167 | "1254", 168 | "1255", 169 | "1256", 170 | "1257", 171 | "1258", 172 | "1259", 173 | "1260", 174 | "1265", 175 | "1267", 176 | "1268", 177 | "1269", 178 | "1270", 179 | "1273", 180 | "1274", 181 | "1277", 182 | "1280", 183 | "1282", 184 | "1285", 185 | "1286", 186 | "1287", 187 | "1289", 188 | "1290", 189 | "1292", 190 | "1293", 191 | "1297", 192 | "1298", 193 | "1300", 194 | "1301", 195 | "1302", 196 | "1308", 197 | "1309", 198 | "1312", 199 | "1316", 200 | "1317", 201 | "1323", 202 | "1324", 203 | "1325", 204 | "1326", 205 | "1329", 206 | "1332", 207 | "1336", 208 | "1337", 209 | "1338", 210 | "1341", 211 | "1342", 212 | "1343", 213 | "1345", 214 | "1348", 215 | "1349", 216 | "1350", 217 | "1351", 218 | "1352", 219 | "1353", 220 | "1354", 221 | "1355", 222 | "1356", 223 | "1358", 224 | "1359", 225 | "1363", 226 | "1364", 227 | "1368", 228 | "1369", 229 | "1370", 230 | "1371", 231 | "1373", 232 | "1374", 233 | "1375", 234 | "1377", 235 | "1378", 236 | "1381", 237 | "1383", 238 | "1385", 239 | "1388", 240 | "1393", 241 | "1394", 242 | "1396", 243 | "1397", 244 | "1398", 245 | "1399", 246 | "1400", 247 | "1402", 248 | "1403", 249 | "1406", 250 | "1407", 251 | "1408", 252 | "1409", 253 | "1413", 254 | "1414", 255 | "1416", 256 | "1417", 257 | "1418", 258 | "1419", 259 | "1420", 260 | "1421", 261 | "1423", 262 | "1427", 263 | "1429", 264 | "1430", 265 | "1432", 266 | "1434", 267 | "1435", 268 | "1436", 269 | "1437", 270 | "1438", 271 | "1440", 272 | "1443", 273 | "1444", 274 | "1446", 275 | "1447", 276 | "1448", 277 | "1449", 278 | "1450", 279 | "1451", 280 | "1456", 281 | "1457", 282 | "1463", 283 | "1464", 284 | "1466", 285 | "1468", 286 | "1470", 287 | "1471", 288 | "1472", 289 | "1474", 290 | "1475", 291 | "1476", 292 | "1477", 293 | "1478", 294 | "1484", 295 | "1485", 296 | "1487", 297 | "1488", 298 | "1490", 299 | "1491", 300 | "1492", 301 | "1494", 302 | "1495", 303 | "1496", 304 | "1498", 305 | "1500", 306 | "1501", 307 | "1502", 308 | "1505", 309 | "1506", 310 | "1508", 311 | "1509", 312 | "1510", 313 | "1511", 314 | "1512", 315 | "1514", 316 | "1515", 317 | "1516", 318 | "1517", 319 | "1518", 320 | "1519", 321 | "1521", 322 | "1523", 323 | "1525", 324 | "1526", 325 | "1528", 326 | "1529", 327 | "1530", 328 | "1531", 329 | "1534", 330 | "1537", 331 | "1538", 332 | "1539", 333 | "1540", 334 | "1541", 335 | "1542", 336 | "1543", 337 | "1544", 338 | "1545", 339 | "1546", 340 | "1548", 341 | "1550", 342 | "1551", 343 | "1553", 344 | "1556", 345 | "1557", 346 | "1558", 347 | "1559", 348 | "1560", 349 | "1561", 350 | "1563", 351 | "1565", 352 | "1567", 353 | "1568", 354 | "1569", 355 | "1572", 356 | "1574", 357 | "1578", 358 | "1579", 359 | "1582", 360 | "1583", 361 | "1584", 362 | "1585", 363 | "1588", 364 | "1589", 365 | "1591", 366 | "1594", 367 | "1595", 368 | "1598", 369 | "1600", 370 | "1606", 371 | "1607", 372 | "1608", 373 | "1609", 374 | "1610", 375 | "1611", 376 | "1612", 377 | "1613", 378 | "1614", 379 | "1615", 380 | "1617", 381 | "1618", 382 | "1620", 383 | "1623", 384 | "1626", 385 | "1628", 386 | "1629", 387 | "1630", 388 | "1634", 389 | "1636", 390 | "1637", 391 | "1639", 392 | "1640", 393 | "1641", 394 | "1643", 395 | "1644", 396 | "1645", 397 | "1646", 398 | "1648", 399 | "1652", 400 | "1653", 401 | "1655", 402 | "1657", 403 | "1660", 404 | "1661", 405 | "1662", 406 | "1663", 407 | "1664", 408 | "1666", 409 | "1668", 410 | "1669", 411 | "1672", 412 | "1673", 413 | "1674", 414 | "1675", 415 | "1676", 416 | "1681", 417 | "1683", 418 | "1684", 419 | "1685", 420 | "1686", 421 | "1687", 422 | "1688", 423 | "1689", 424 | "1690", 425 | "1692", 426 | "1694", 427 | "1695", 428 | "1697", 429 | "1698", 430 | "1699", 431 | "1701", 432 | "1702", 433 | "1703", 434 | "1704", 435 | "1707", 436 | "1710", 437 | "1711", 438 | "1712", 439 | "1713", 440 | "1714", 441 | "1716", 442 | "1718", 443 | "1719", 444 | "1720", 445 | "1721", 446 | "1722", 447 | "1724", 448 | "1725", 449 | "1727", 450 | "1728", 451 | "1729", 452 | "1730", 453 | "1731", 454 | "1732", 455 | "1734", 456 | "1735", 457 | "1737", 458 | "1738", 459 | "1739", 460 | "1740", 461 | "1741", 462 | "1742", 463 | "1746", 464 | "1750", 465 | "1754", 466 | "1756", 467 | "1758", 468 | "1759", 469 | "1760", 470 | "1761", 471 | "1762", 472 | "1763", 473 | "1766", 474 | "1767", 475 | "1768", 476 | "1770", 477 | "1771", 478 | "1772", 479 | "1774", 480 | "1775", 481 | "1776", 482 | "1777", 483 | "1778", 484 | "1779", 485 | "1780", 486 | "1782", 487 | "1783", 488 | "1784", 489 | "1785", 490 | "1786", 491 | "1787", 492 | "1788", 493 | "1790", 494 | "1792", 495 | "1793", 496 | "1796", 497 | "1797", 498 | "1799", 499 | "1800", 500 | "1801", 501 | "1804", 502 | "1805", 503 | "1806", 504 | "1807", 505 | "1808", 506 | "1809", 507 | "1810", 508 | "1811", 509 | "1812", 510 | "1816", 511 | "1817", 512 | "1820", 513 | "1821", 514 | "1822", 515 | "1823", 516 | "1824", 517 | "1825", 518 | "1826", 519 | "1828", 520 | "1829", 521 | "1831", 522 | "1832", 523 | "1833", 524 | "1834", 525 | "1835", 526 | "1836", 527 | "1837", 528 | "1838", 529 | "1839", 530 | "1840", 531 | "1841", 532 | "1842", 533 | "1843", 534 | "1844", 535 | "1845", 536 | "1846", 537 | "1849", 538 | "1852", 539 | "1853", 540 | "1854", 541 | "1855", 542 | "1857", 543 | "1858", 544 | "1859", 545 | "1860", 546 | "1861", 547 | "1863", 548 | "1864", 549 | "1868", 550 | "1870", 551 | "1872", 552 | "1873", 553 | "1875", 554 | "1883", 555 | "1884", 556 | "1885", 557 | "1887", 558 | "1888", 559 | "1889", 560 | "1890", 561 | "1891", 562 | "1893", 563 | "1894", 564 | "1897", 565 | "1901", 566 | "1902", 567 | "1903", 568 | "1904", 569 | "1905", 570 | "1907", 571 | "1908", 572 | "1909", 573 | "1910", 574 | "1911", 575 | "1912", 576 | "1913", 577 | "1915", 578 | "1919", 579 | "1920", 580 | "1921", 581 | "1922", 582 | "1923", 583 | "1924", 584 | "1925", 585 | "1927", 586 | "1934", 587 | "1935", 588 | "1936", 589 | "1937", 590 | "1938", 591 | "1939", 592 | "1940", 593 | "1942", 594 | "1943", 595 | "1945", 596 | "1946", 597 | "1947", 598 | "1948", 599 | "1949", 600 | "1951", 601 | "1952", 602 | "1954", 603 | "1955", 604 | "1956", 605 | "1957", 606 | "1959", 607 | "1960", 608 | "1961", 609 | "1962", 610 | "1964", 611 | "1965", 612 | "1966", 613 | "1967", 614 | "1968", 615 | "1969", 616 | "1970", 617 | "1971", 618 | "1972", 619 | "1973", 620 | "1974", 621 | "1975", 622 | "1976", 623 | "1977", 624 | "1978", 625 | "1979", 626 | "1980", 627 | "1981", 628 | "1982", 629 | "1983", 630 | "1984", 631 | "1986", 632 | "1987", 633 | "1989", 634 | "1990", 635 | "1991", 636 | "1992", 637 | "1993", 638 | "1994", 639 | "1995", 640 | "1998", 641 | "1999", 642 | "2000", 643 | "2001", 644 | "2002", 645 | "2003", 646 | "2007", 647 | "2009", 648 | "2010", 649 | "2011", 650 | "2012", 651 | "2013", 652 | "2014", 653 | "2015", 654 | "2016", 655 | "2017", 656 | "2018", 657 | "2021", 658 | "2022", 659 | "2023", 660 | "2024", 661 | "2025", 662 | "2026", 663 | "2027", 664 | "2028", 665 | "2029", 666 | "2030", 667 | "2031", 668 | "2032", 669 | "2033", 670 | "2034", 671 | "2035", 672 | "2036", 673 | "2037", 674 | "2038", 675 | "2039", 676 | "2040", 677 | "2041", 678 | "2042", 679 | "2043", 680 | "2044", 681 | "2045", 682 | "2046", 683 | "2047", 684 | "2048", 685 | "2049", 686 | "2050", 687 | "2051", 688 | "2052", 689 | "2054", 690 | "2055", 691 | "2056", 692 | "2057", 693 | "2058", 694 | "2059", 695 | "2060", 696 | "2061", 697 | "2062", 698 | "2063", 699 | "2064", 700 | "2065", 701 | "2066", 702 | "2067", 703 | "2068", 704 | "2069", 705 | "2070", 706 | "2071", 707 | "2072", 708 | "2074", 709 | "2075", 710 | "2076", 711 | "2078", 712 | "2081", 713 | "2082", 714 | "2083", 715 | "2084", 716 | "2088", 717 | "2090", 718 | "2091", 719 | "2093", 720 | "2095", 721 | "2096", 722 | "2097", 723 | "2098", 724 | "2100", 725 | "2102", 726 | "2103", 727 | "2109", 728 | "2112", 729 | "2113", 730 | "2116", 731 | "2118", 732 | "2120", 733 | "2121", 734 | "2124", 735 | "2125", 736 | "2126", 737 | "2131", 738 | "2132", 739 | "2135", 740 | "2137", 741 | "2138", 742 | "2139", 743 | "2140", 744 | "2141", 745 | "2142", 746 | "2145", 747 | "2147", 748 | "2148", 749 | "2149", 750 | "2150", 751 | "2151", 752 | "2152", 753 | "2154", 754 | "2156", 755 | "2157", 756 | "2159", 757 | "2160", 758 | "2161", 759 | "2162", 760 | "2165", 761 | "2166", 762 | "2167", 763 | "2168", 764 | "2169", 765 | "2170", 766 | "2171", 767 | "2175", 768 | "2176", 769 | "2177", 770 | "2179", 771 | "2180", 772 | "2181", 773 | "2182", 774 | "2183", 775 | "2186", 776 | "2187", 777 | "2188", 778 | "2190", 779 | "2191", 780 | "2192", 781 | "2194", 782 | "2195", 783 | "2197", 784 | "2198", 785 | "2199", 786 | "2202", 787 | "2203", 788 | "2204", 789 | "2205", 790 | "2206", 791 | "2207", 792 | "2209", 793 | "2211", 794 | "2212", 795 | "2213", 796 | "2216", 797 | "2218", 798 | "2220", 799 | "2222", 800 | "2223", 801 | "2224", 802 | "2227", 803 | "2228", 804 | "2229", 805 | "2230", 806 | "2231", 807 | "2237", 808 | "2239", 809 | "2240", 810 | "2241", 811 | "2243", 812 | "2244", 813 | "2246", 814 | "2247", 815 | "2248", 816 | "2249", 817 | "2251", 818 | "2252", 819 | "2253", 820 | "2256", 821 | "2258", 822 | "2259", 823 | "2260", 824 | "2263", 825 | "2264", 826 | "2265", 827 | "2266", 828 | "2268", 829 | "2269", 830 | "2270", 831 | "2272", 832 | "2273", 833 | "2274", 834 | "2275", 835 | "2276", 836 | "2277", 837 | "2278", 838 | "2280", 839 | "2281", 840 | "2284", 841 | "2287", 842 | "2288", 843 | "2290", 844 | "2291", 845 | "2292", 846 | "2293", 847 | "2294", 848 | "2295", 849 | "2296", 850 | "2297", 851 | "2299", 852 | "2303", 853 | "2304", 854 | "2305", 855 | "2307", 856 | "2308", 857 | "2311", 858 | "2312", 859 | "2313", 860 | "2314", 861 | "2315", 862 | "2316", 863 | "2317", 864 | "2318", 865 | "2319", 866 | "2321", 867 | "2322", 868 | "2323", 869 | "2324", 870 | "2325", 871 | "2326", 872 | "2327", 873 | "2329", 874 | "2330", 875 | "2331", 876 | "2332", 877 | "2333", 878 | "2334", 879 | "2337", 880 | "2340", 881 | "2341", 882 | "2342", 883 | "2343", 884 | "2344", 885 | "2345", 886 | "2346", 887 | "2347", 888 | "2350", 889 | "2357", 890 | "2360", 891 | "2361", 892 | "2364", 893 | "2367", 894 | "2368", 895 | "2371", 896 | "2372", 897 | "2374", 898 | "2375", 899 | "2377", 900 | "2378", 901 | "2379", 902 | "2380", 903 | "2381", 904 | "2382", 905 | "2383", 906 | "2385", 907 | "2386", 908 | "2388", 909 | "2389", 910 | "2390", 911 | "2391", 912 | "2392", 913 | "2393", 914 | "2395", 915 | "2397", 916 | "2398", 917 | "2399", 918 | "2401", 919 | "2402", 920 | "2403", 921 | "2405", 922 | "2406", 923 | "2407", 924 | "2408", 925 | "2409", 926 | "2410", 927 | "2411", 928 | "2412", 929 | "2413", 930 | "2414", 931 | "2416", 932 | "2418", 933 | "2419", 934 | "2421", 935 | "2422", 936 | "2423", 937 | "2426", 938 | "2430", 939 | "2431", 940 | "2432", 941 | "2433", 942 | "2434", 943 | "2435", 944 | "2436", 945 | "2437", 946 | "2438", 947 | "2439", 948 | "2442", 949 | "2443", 950 | "2444", 951 | "2446", 952 | "2447", 953 | "2448", 954 | "5003", 955 | "5004", 956 | "5005", 957 | "5007", 958 | "5008", 959 | "5012", 960 | "5015", 961 | "5016", 962 | "5019", 963 | "5022", 964 | "5023", 965 | "5027", 966 | "5028", 967 | "5035", 968 | "5037", 969 | "5038", 970 | "5039", 971 | "5040", 972 | "5041", 973 | "5043", 974 | "5044", 975 | "5045", 976 | "5046", 977 | "5047", 978 | "5048", 979 | "5051", 980 | "5052", 981 | "5053", 982 | "5056", 983 | "5057", 984 | "5060", 985 | "5062", 986 | "5063", 987 | "5064", 988 | "5065", 989 | "5066", 990 | "5071", 991 | "5072", 992 | "5073", 993 | "5076", 994 | "5077", 995 | "5078", 996 | "5079", 997 | "5080", 998 | "5081", 999 | "5082", 1000 | "5097", 1001 | "5103", 1002 | "5104", 1003 | "5105", 1004 | "5111", 1005 | "5121", 1006 | "5126", 1007 | "5147", 1008 | "5163", 1009 | "5164", 1010 | "5165", 1011 | "5167", 1012 | "5168", 1013 | "5172", 1014 | "5173", 1015 | "5178", 1016 | "5179", 1017 | "5181", 1018 | "5182", 1019 | "5183", 1020 | "5188", 1021 | "5189", 1022 | "5192", 1023 | "5198", 1024 | "5199", 1025 | "5206", 1026 | "5207", 1027 | "5215", 1028 | "5216", 1029 | "5217", 1030 | "5228", 1031 | "5231", 1032 | "5234", 1033 | "5237", 1034 | "5238", 1035 | "5242", 1036 | "5243", 1037 | "5244", 1038 | "5245", 1039 | "5253", 1040 | "5254", 1041 | "5255", 1042 | "5290", 1043 | "5296", 1044 | "5302", 1045 | "5304", 1046 | "5310", 1047 | "5314", 1048 | "5319", 1049 | "5325", 1050 | "5329", 1051 | "5330", 1052 | "5333", 1053 | "5334", 1054 | "5338", 1055 | "5355", 1056 | "5361", 1057 | "5365", 1058 | "5375", 1059 | "5382", 1060 | "5389", 1061 | "5396", 1062 | "5403", 1063 | "5412", 1064 | "5422", 1065 | "5423", 1066 | "5424", 1067 | "5425", 1068 | "5426", 1069 | "5438", 1070 | "5445", 1071 | "5451", 1072 | "5452", 1073 | "5454", 1074 | "5456", 1075 | "5457", 1076 | "5460", 1077 | "5461", 1078 | "5462", 1079 | "5464", 1080 | "5474", 1081 | "5479", 1082 | "5480", 1083 | "5481", 1084 | "5484", 1085 | "5485", 1086 | "5487", 1087 | "5502", 1088 | "5508", 1089 | "5511", 1090 | "5513", 1091 | "5527", 1092 | "5528", 1093 | "5529", 1094 | "5530", 1095 | "5531", 1096 | "5533", 1097 | "5536", 1098 | "5538", 1099 | "5542", 1100 | "5551", 1101 | "5553", 1102 | "5555", 1103 | "5556", 1104 | "5560", 1105 | "5562", 1106 | "5563", 1107 | "5564", 1108 | "5565", 1109 | "5569", 1110 | "5575", 1111 | "5577", 1112 | "5583", 1113 | "5584", 1114 | "5586", 1115 | "5587", 1116 | "5588", 1117 | "5589", 1118 | "5591", 1119 | "5594", 1120 | "5595", 1121 | "5596", 1122 | "5597", 1123 | "5604", 1124 | "5607", 1125 | "5609", 1126 | "5611", 1127 | "5612", 1128 | "5614", 1129 | "5616", 1130 | "5617", 1131 | "5618", 1132 | "5619", 1133 | "5620", 1134 | "5624", 1135 | "5626", 1136 | "5628", 1137 | "5629", 1138 | "5630", 1139 | "5634", 1140 | "5635", 1141 | "5636", 1142 | "5641", 1143 | "5646", 1144 | "5651", 1145 | "5653", 1146 | "5654", 1147 | "5660", 1148 | "5663", 1149 | "5666", 1150 | "5668", 1151 | "5674", 1152 | "5675", 1153 | "5676", 1154 | "5686", 1155 | "5688", 1156 | "5689", 1157 | "5692", 1158 | "5705", 1159 | "5720", 1160 | "5723", 1161 | "5724", 1162 | "5729", 1163 | "5741", 1164 | "5744", 1165 | "5749", 1166 | "5755", 1167 | "5761", 1168 | "5762", 1169 | "5763", 1170 | "5766", 1171 | "5767", 1172 | "5770", 1173 | "5773", 1174 | "5778", 1175 | "5786", 1176 | "5787", 1177 | "5790", 1178 | "5792", 1179 | "5795", 1180 | "5796", 1181 | "5797", 1182 | "5809", 1183 | "5810", 1184 | "5818", 1185 | "5822", 1186 | "5828", 1187 | "5829", 1188 | "5836", 1189 | "5855", 1190 | "5859", 1191 | "5862", 1192 | "5864", 1193 | "5870", 1194 | "5874", 1195 | "5882", 1196 | "5884", 1197 | "5890", 1198 | "5898", 1199 | "5901", 1200 | "5924", 1201 | "5933", 1202 | "5938", 1203 | "5941", 1204 | "5944", 1205 | "5945", 1206 | "5951", 1207 | "5952", 1208 | "5954", 1209 | "5955", 1210 | "5957", 1211 | "5958", 1212 | "5959", 1213 | "5960", 1214 | "5964", 1215 | "5975", 1216 | "5977", 1217 | "5978", 1218 | "5979", 1219 | "5981", 1220 | "5982", 1221 | "5984", 1222 | "5989", 1223 | "5992", 1224 | "5995", 1225 | "5999", 1226 | "6001", 1227 | "6002", 1228 | "6003", 1229 | "6004", 1230 | "6005", 1231 | "6006", 1232 | "6007", 1233 | "6008", 1234 | "6011", 1235 | "6013", 1236 | "6014", 1237 | "6015", 1238 | "6016", 1239 | "6017", 1240 | "6018", 1241 | "6019", 1242 | "6022", 1243 | "6025", 1244 | "6032", 1245 | "6041", 1246 | "6043", 1247 | "6044", 1248 | "6045", 1249 | "6046", 1250 | "6048", 1251 | "6049", 1252 | "6050", 1253 | "6051", 1254 | "6052", 1255 | "6053", 1256 | "6054", 1257 | "6055", 1258 | "6056", 1259 | "6057", 1260 | "6058", 1261 | "6059", 1262 | "6060", 1263 | "6062", 1264 | "6063", 1265 | "6065", 1266 | "6066", 1267 | "6068", 1268 | "6069", 1269 | "6070", 1270 | "6072", 1271 | "6073", 1272 | "6074", 1273 | "6078", 1274 | "6079", 1275 | "6080", 1276 | "6081", 1277 | "6082", 1278 | "6095", 1279 | "6096", 1280 | "6097", 1281 | "6099", 1282 | "6100", 1283 | "6101", 1284 | "6102", 1285 | "6103", 1286 | "6105", 1287 | "6107", 1288 | "6108", 1289 | "6109", 1290 | "6110", 1291 | "6112", 1292 | "6114", 1293 | "6116", 1294 | "6117", 1295 | "6119", 1296 | "6120", 1297 | "6121", 1298 | "6122", 1299 | "6124", 1300 | "6125", 1301 | "6134", 1302 | "6135", 1303 | "6136", 1304 | "6137", 1305 | "6138", 1306 | "6139", 1307 | "6140", 1308 | "6141", 1309 | "6143", 1310 | "6144", 1311 | "6146", 1312 | "6149", 1313 | "6150", 1314 | "6151", 1315 | "6152", 1316 | "6153", 1317 | "6155", 1318 | "6160", 1319 | "6161", 1320 | "6167", 1321 | "6170", 1322 | "6175", 1323 | "6176", 1324 | "6177", 1325 | "6178", 1326 | "6180", 1327 | "6181", 1328 | "6182", 1329 | "6183", 1330 | "6184", 1331 | "6186", 1332 | "6187", 1333 | "6189", 1334 | "6201", 1335 | "6202", 1336 | "6204", 1337 | "6205", 1338 | "6206", 1339 | "6207", 1340 | "6208", 1341 | "6209", 1342 | "6210", 1343 | "6211", 1344 | "6213", 1345 | "6215", 1346 | "6216", 1347 | "6217", 1348 | "6218", 1349 | "6222", 1350 | "6228", 1351 | "6229", 1352 | "6230", 1353 | "6231", 1354 | "6232", 1355 | "6233", 1356 | "6234", 1357 | "6235", 1358 | "6241", 1359 | "6244", 1360 | "6248", 1361 | "6254", 1362 | "6255", 1363 | "6256", 1364 | "6257", 1365 | "6258", 1366 | "6259", 1367 | "6260", 1368 | "6262", 1369 | "6263", 1370 | "6264", 1371 | "6265", 1372 | "6266", 1373 | "6267", 1374 | "6269", 1375 | "6271", 1376 | "6272", 1377 | "6275", 1378 | "6276", 1379 | "6279", 1380 | "6280", 1381 | "6281", 1382 | "6282", 1383 | "6283", 1384 | "6284", 1385 | "6285", 1386 | "6287", 1387 | "6290", 1388 | "6291", 1389 | "6292", 1390 | "6293", 1391 | "6294", 1392 | "6295", 1393 | "6296", 1394 | "6298", 1395 | "6300", 1396 | "6301", 1397 | "6302", 1398 | "6303", 1399 | "6304", 1400 | "6311", 1401 | "6313", 1402 | "6315", 1403 | "6316", 1404 | "6317", 1405 | "6318", 1406 | "6319", 1407 | "6320", 1408 | "6321", 1409 | "6324", 1410 | "6325", 1411 | "6326", 1412 | "6339", 1413 | "6340", 1414 | "6341", 1415 | "6342", 1416 | "6344", 1417 | "6345", 1418 | "6346", 1419 | "6347", 1420 | "6348", 1421 | "6349", 1422 | "6350", 1423 | "6351", 1424 | "6352", 1425 | "6355", 1426 | "6356", 1427 | "6358", 1428 | "6359", 1429 | "6360", 1430 | "6361", 1431 | "6362", 1432 | "6363", 1433 | "6364", 1434 | "6365", 1435 | "6366", 1436 | "6367", 1437 | "6368", 1438 | "6371", 1439 | "6372", 1440 | "6374", 1441 | "6375", 1442 | "6376", 1443 | "6377", 1444 | "6378", 1445 | "6379", 1446 | "6380", 1447 | "6381", 1448 | "6382", 1449 | "6383", 1450 | "6384", 1451 | "6386", 1452 | "6387", 1453 | "6388", 1454 | "6389", 1455 | "6402", 1456 | "6409", 1457 | "6410", 1458 | "6424", 1459 | "6435", 1460 | "6436", 1461 | "6441", 1462 | "6443", 1463 | "6457", 1464 | "6459", 1465 | "6460", 1466 | "6465", 1467 | "6470", 1468 | "6473", 1469 | "6488", 1470 | "6491", 1471 | "6495", 1472 | "6496", 1473 | "6498", 1474 | "6500", 1475 | "6503", 1476 | "6504", 1477 | "6510", 1478 | "6512", 1479 | "6519", 1480 | "6524", 1481 | "6525", 1482 | "6527", 1483 | "6528", 1484 | "6531", 1485 | "6543", 1486 | "6545", 1487 | "6561", 1488 | "6565", 1489 | "6566", 1490 | "6575", 1491 | "6578", 1492 | "6579", 1493 | "6587", 1494 | "6588", 1495 | "6589", 1496 | "6590", 1497 | "6600", 1498 | "6607", 1499 | "7001", 1500 | "7002", 1501 | "7003", 1502 | "7004", 1503 | "7005", 1504 | "7006", 1505 | "7008", 1506 | "7009", 1507 | "7010", 1508 | "7011", 1509 | "7012", 1510 | "7013", 1511 | "7015", 1512 | "7016", 1513 | "7017", 1514 | "7018", 1515 | "7019", 1516 | "7020", 1517 | "7021", 1518 | "7023", 1519 | "11935", 1520 | "11932", 1521 | "13942", 1522 | "13735", 1523 | "13730", 1524 | "13419", 1525 | "12078", 1526 | "14752", 1527 | "14737", 1528 | "14727", 1529 | "14719", 1530 | "14718", 1531 | "14669", 1532 | "14661", 1533 | "14647", 1534 | "14642", 1535 | "14632", 1536 | "14623", 1537 | "14613", 1538 | "14612", 1539 | "14603", 1540 | "14602", 1541 | "14599", 1542 | "14569", 1543 | "14560", 1544 | "14549", 1545 | "14542", 1546 | "14517", 1547 | "14508", 1548 | "14498", 1549 | "14489", 1550 | "14484", 1551 | "14478", 1552 | "14456", 1553 | "14434", 1554 | "14313", 1555 | "14312", 1556 | "14246", 1557 | "14111", 1558 | "14108", 1559 | "14097", 1560 | "14086", 1561 | "14068", 1562 | "14066", 1563 | "14059", 1564 | "14048", 1565 | "14046", 1566 | "14004", 1567 | "13986", 1568 | "13980", 1569 | "13925", 1570 | "13868", 1571 | "13763", 1572 | "13758", 1573 | "13678", 1574 | "13645", 1575 | "13581", 1576 | "13222", 1577 | "13208", 1578 | "13201", 1579 | "12986", 1580 | "12878", 1581 | "12861", 1582 | "12801", 1583 | "12686", 1584 | "12657", 1585 | "12623", 1586 | "14197", 1587 | "14196", 1588 | "14190", 1589 | "14188", 1590 | "14181", 1591 | "14171", 1592 | "14168", 1593 | "14145", 1594 | "14793", 1595 | "14792", 1596 | "14791", 1597 | "14790", 1598 | "14788", 1599 | "14787", 1600 | "14786", 1601 | "14784", 1602 | "14783", 1603 | "14782", 1604 | "14781", 1605 | "11566", 1606 | "13192", 1607 | "12277", 1608 | "12198", 1609 | "11573", 1610 | "14765", 1611 | "14700", 1612 | "14646", 1613 | "14523", 1614 | "14506", 1615 | "14504", 1616 | "14497", 1617 | "14451", 1618 | "14446", 1619 | "14436", 1620 | "14429", 1621 | "14362", 1622 | "14354", 1623 | "14344", 1624 | "14340", 1625 | "14339", 1626 | "14332", 1627 | "14309", 1628 | "14256", 1629 | "14254", 1630 | "14126", 1631 | "14124", 1632 | "14107", 1633 | "14105", 1634 | "14099", 1635 | "14096", 1636 | "14091", 1637 | "14090", 1638 | "14085", 1639 | "14084", 1640 | "14083", 1641 | "14074", 1642 | "14073", 1643 | "14072", 1644 | "14067", 1645 | "14060", 1646 | "14047", 1647 | "14015", 1648 | "14011", 1649 | "14007", 1650 | "14006", 1651 | "14005", 1652 | "13991", 1653 | "13984", 1654 | "13974", 1655 | "13973", 1656 | "13967", 1657 | "13933", 1658 | "13932", 1659 | "13924", 1660 | "13911", 1661 | "13907", 1662 | "13906", 1663 | "13897", 1664 | "13887", 1665 | "13886", 1666 | "13885", 1667 | "13871", 1668 | "13860", 1669 | "13859", 1670 | "13853", 1671 | "13841", 1672 | "13839", 1673 | "13830", 1674 | "13826", 1675 | "13824", 1676 | "13818", 1677 | "13788", 1678 | "13773", 1679 | "13770", 1680 | "13769", 1681 | "13765", 1682 | "13747", 1683 | "13745", 1684 | "13731", 1685 | "13687", 1686 | "13661", 1687 | "13660", 1688 | "13649", 1689 | "13646", 1690 | "13643", 1691 | "13640", 1692 | "13633", 1693 | "13631", 1694 | "13598", 1695 | "13591", 1696 | "13580", 1697 | "13547", 1698 | "13520", 1699 | "13519", 1700 | "13485", 1701 | "13467", 1702 | "13439", 1703 | "13414", 1704 | "13400", 1705 | "13394", 1706 | "13389", 1707 | "13288", 1708 | "13281", 1709 | "13280", 1710 | "13261", 1711 | "13249", 1712 | "13245", 1713 | "13238", 1714 | "13212", 1715 | "13209", 1716 | "13202", 1717 | "13200", 1718 | "13158", 1719 | "13151", 1720 | "13149", 1721 | "13004", 1722 | "12814", 1723 | "12773", 1724 | "12734", 1725 | "12724", 1726 | "12706", 1727 | "12692", 1728 | "12660", 1729 | "12658", 1730 | "12653", 1731 | "12646", 1732 | "12524", 1733 | "12523", 1734 | "12516", 1735 | "12496", 1736 | "12462", 1737 | "12444", 1738 | "12435", 1739 | "12424", 1740 | "12395", 1741 | "12390", 1742 | "12097", 1743 | "11782", 1744 | "11575", 1745 | "11601", 1746 | "12025", 1747 | "12024", 1748 | "12023", 1749 | "11862", 1750 | "14774", 1751 | "14741", 1752 | "14740", 1753 | "14739", 1754 | "14736", 1755 | "14734", 1756 | "14733", 1757 | "14732", 1758 | "14721", 1759 | "14686", 1760 | "14685", 1761 | "14680", 1762 | "14666", 1763 | "14664", 1764 | "14663", 1765 | "14653", 1766 | "14652", 1767 | "14630", 1768 | "14617", 1769 | "14611", 1770 | "14608", 1771 | "14597", 1772 | "14596", 1773 | "14592", 1774 | "14589", 1775 | "14582", 1776 | "14572", 1777 | "14561", 1778 | "14559", 1779 | "14555", 1780 | "14552", 1781 | "14491", 1782 | "14487", 1783 | "14479", 1784 | "14477", 1785 | "14438", 1786 | "14195", 1787 | "14194", 1788 | "14187", 1789 | "14186", 1790 | "14184", 1791 | "14182", 1792 | "14179", 1793 | "14178", 1794 | "14174", 1795 | "14169", 1796 | "14164", 1797 | "14162", 1798 | "14156", 1799 | "14143", 1800 | "14132", 1801 | "14129", 1802 | "14128", 1803 | "13716", 1804 | "13708", 1805 | "13707", 1806 | "13702", 1807 | "13195", 1808 | "12290", 1809 | "12261", 1810 | "12260", 1811 | "12257", 1812 | "11941", 1813 | "11939", 1814 | "11934", 1815 | "11931", 1816 | "11766", 1817 | "12026", 1818 | "12006", 1819 | "11653", 1820 | "11580", 1821 | "11567", 1822 | "12050", 1823 | "12048", 1824 | "12047", 1825 | "12039", 1826 | "11999", 1827 | "14730", 1828 | "14729", 1829 | "14708", 1830 | "14513", 1831 | "14511", 1832 | "14507", 1833 | "14505", 1834 | "14503", 1835 | "14499", 1836 | "14495", 1837 | "14455", 1838 | "14449", 1839 | "14417", 1840 | "14399", 1841 | "14396", 1842 | "14394", 1843 | "14390", 1844 | "14378", 1845 | "14373", 1846 | "14366", 1847 | "14331", 1848 | "14324", 1849 | "14322", 1850 | "14319", 1851 | "14310", 1852 | "14301", 1853 | "14297", 1854 | "14295", 1855 | "14294", 1856 | "14291", 1857 | "14289", 1858 | "14264", 1859 | "14259", 1860 | "14258", 1861 | "14244", 1862 | "14234", 1863 | "14232", 1864 | "14229", 1865 | "14228", 1866 | "14226", 1867 | "14211", 1868 | "14125", 1869 | "14123", 1870 | "14122", 1871 | "14114", 1872 | "14104", 1873 | "14102", 1874 | "14095", 1875 | "14093", 1876 | "14092", 1877 | "14079", 1878 | "14077", 1879 | "14071", 1880 | "14061", 1881 | "14058", 1882 | "14057", 1883 | "14056", 1884 | "14044", 1885 | "14043", 1886 | "14034", 1887 | "14026", 1888 | "14018", 1889 | "14012", 1890 | "14010", 1891 | "13997", 1892 | "13995", 1893 | "13985", 1894 | "13983", 1895 | "13982", 1896 | "13981", 1897 | "13978", 1898 | "13971", 1899 | "13965", 1900 | "13948", 1901 | "13947", 1902 | "13940", 1903 | "13939", 1904 | "13935", 1905 | "13931", 1906 | "13923", 1907 | "13914", 1908 | "13905", 1909 | "13896", 1910 | "13895", 1911 | "13892", 1912 | "13884", 1913 | "13879", 1914 | "13852", 1915 | "13844", 1916 | "13822", 1917 | "13821", 1918 | "13819", 1919 | "13814", 1920 | "13809", 1921 | "13799", 1922 | "13779", 1923 | "13754", 1924 | "13749", 1925 | "13746", 1926 | "13744", 1927 | "13728", 1928 | "13691", 1929 | "13670", 1930 | "13653", 1931 | "13650", 1932 | "13648", 1933 | "13642", 1934 | "13636", 1935 | "13622", 1936 | "13618", 1937 | "13615", 1938 | "13602", 1939 | "13600", 1940 | "13590", 1941 | "13582", 1942 | "13566", 1943 | "13546", 1944 | "13545", 1945 | "13543", 1946 | "13540", 1947 | "13537", 1948 | "13534", 1949 | "13532", 1950 | "13516", 1951 | "13515", 1952 | "13513", 1953 | "13508", 1954 | "13493", 1955 | "13489", 1956 | "13487", 1957 | "13472", 1958 | "13468", 1959 | "13462", 1960 | "13454", 1961 | "13426", 1962 | "13403", 1963 | "13402", 1964 | "13397", 1965 | "13383", 1966 | "13374", 1967 | "13366", 1968 | "13339", 1969 | "13332", 1970 | "13319", 1971 | "13316", 1972 | "13301", 1973 | "13289", 1974 | "13269", 1975 | "13252", 1976 | "13242", 1977 | "13239", 1978 | "13236", 1979 | "13218", 1980 | "13217", 1981 | "13207", 1982 | "13205", 1983 | "13204", 1984 | "13203", 1985 | "13183", 1986 | "13180", 1987 | "13161", 1988 | "13152", 1989 | "13150", 1990 | "13145", 1991 | "13135", 1992 | "13119", 1993 | "13117", 1994 | "13054", 1995 | "13050", 1996 | "13037", 1997 | "13025", 1998 | "13017", 1999 | "13012", 2000 | "13009", 2001 | "12995", 2002 | "12994", 2003 | "12988", 2004 | "12987", 2005 | "12968", 2006 | "12967", 2007 | "12937", 2008 | "12914", 2009 | "12907", 2010 | "12903", 2011 | "12891", 2012 | "12883", 2013 | "12882", 2014 | "12859", 2015 | "12858", 2016 | "12855", 2017 | "12854", 2018 | "12852", 2019 | "12846", 2020 | "12844", 2021 | "12843", 2022 | "12834", 2023 | "12833", 2024 | "12826", 2025 | "12816", 2026 | "12813", 2027 | "12812", 2028 | "12809", 2029 | "12807", 2030 | "12802", 2031 | "12800", 2032 | "12799", 2033 | "12761", 2034 | "12730", 2035 | "12728", 2036 | "12717", 2037 | "12693", 2038 | "12679", 2039 | "12672", 2040 | "12661", 2041 | "12659", 2042 | "12656", 2043 | "12634", 2044 | "12629", 2045 | "12626", 2046 | "12610", 2047 | "12606", 2048 | "12602", 2049 | "12597", 2050 | "12525", 2051 | "12502", 2052 | "12478", 2053 | "12455", 2054 | "12437", 2055 | "12434", 2056 | "12432", 2057 | "12425", 2058 | "12403", 2059 | "12400", 2060 | "12393", 2061 | "12382", 2062 | "12348", 2063 | "12347", 2064 | "12332", 2065 | "12321", 2066 | "12292", 2067 | "12207", 2068 | "12133", 2069 | "11688", 2070 | "11654", 2071 | "11603", 2072 | "11597", 2073 | "13705", 2074 | "13299", 2075 | "13193", 2076 | "12267", 2077 | "12156", 2078 | "11899", 2079 | "11650", 2080 | "11639", 2081 | "11626", 2082 | "11623", 2083 | "11698", 2084 | "11663", 2085 | "11658", 2086 | "11589", 2087 | "12056", 2088 | "12032", 2089 | "12031", 2090 | "12019", 2091 | "12008", 2092 | "14772", 2093 | "14768", 2094 | "14751", 2095 | "14747", 2096 | "14746", 2097 | "14744", 2098 | "14742", 2099 | "14738", 2100 | "14735", 2101 | "14726", 2102 | "14725", 2103 | "14724", 2104 | "14723", 2105 | "14722", 2106 | "14720", 2107 | "14677", 2108 | "14668", 2109 | "14667", 2110 | "14665", 2111 | "14662", 2112 | "14643", 2113 | "14641", 2114 | "14639", 2115 | "14636", 2116 | "14634", 2117 | "14631", 2118 | "14628", 2119 | "14616", 2120 | "14615", 2121 | "14601", 2122 | "14600", 2123 | "14598", 2124 | "14588", 2125 | "14587", 2126 | "14581", 2127 | "14580", 2128 | "14578", 2129 | "14577", 2130 | "14576", 2131 | "14575", 2132 | "14573", 2133 | "14564", 2134 | "14554", 2135 | "14548", 2136 | "14546", 2137 | "14543", 2138 | "14541", 2139 | "14538", 2140 | "14531", 2141 | "14492", 2142 | "14490", 2143 | "14483", 2144 | "14482", 2145 | "14480", 2146 | "14472", 2147 | "14471", 2148 | "14452", 2149 | "14443", 2150 | "14442", 2151 | "14201", 2152 | "14200", 2153 | "14198", 2154 | "14193", 2155 | "14192", 2156 | "14189", 2157 | "14180", 2158 | "14175", 2159 | "14173", 2160 | "14170", 2161 | "14166", 2162 | "14165", 2163 | "14163", 2164 | "14161", 2165 | "14158", 2166 | "14150", 2167 | "14149", 2168 | "14148", 2169 | "14144", 2170 | "14142", 2171 | "14141", 2172 | "14140", 2173 | "14134", 2174 | "14130", 2175 | "14127", 2176 | "12012", 2177 | "11946", 2178 | "11720", 2179 | "11651", 2180 | "11624", 2181 | "11610", 2182 | "14714", 2183 | "14711", 2184 | "14705", 2185 | "14703", 2186 | "14702", 2187 | "14688", 2188 | "14529", 2189 | "14525", 2190 | "14524", 2191 | "14521", 2192 | "14519", 2193 | "14518", 2194 | "14509", 2195 | "14468", 2196 | "14467", 2197 | "14466", 2198 | "14465", 2199 | "14463", 2200 | "14454", 2201 | "14428", 2202 | "14406", 2203 | "14402", 2204 | "14400", 2205 | "14398", 2206 | "14397", 2207 | "14392", 2208 | "14391", 2209 | "14386", 2210 | "14384", 2211 | "14383", 2212 | "14376", 2213 | "14374", 2214 | "14370", 2215 | "14360", 2216 | "14359", 2217 | "14348", 2218 | "14345", 2219 | "14341", 2220 | "14335", 2221 | "14334", 2222 | "14328", 2223 | "14318", 2224 | "14317", 2225 | "14315", 2226 | "14305", 2227 | "14303", 2228 | "14299", 2229 | "14290", 2230 | "14283", 2231 | "14282", 2232 | "14266", 2233 | "14260", 2234 | "14257", 2235 | "14255", 2236 | "14250", 2237 | "14249", 2238 | "14248", 2239 | "14247", 2240 | "14245", 2241 | "14242", 2242 | "14240", 2243 | "14236", 2244 | "14225", 2245 | "14218", 2246 | "14215", 2247 | "14214", 2248 | "14212", 2249 | "14112", 2250 | "14109", 2251 | "14098", 2252 | "14094", 2253 | "14089", 2254 | "14088", 2255 | "14087", 2256 | "14082", 2257 | "14081", 2258 | "14080", 2259 | "14075", 2260 | "14065", 2261 | "14055", 2262 | "14053", 2263 | "14052", 2264 | "14037", 2265 | "14036", 2266 | "14035", 2267 | "14033", 2268 | "14032", 2269 | "14031", 2270 | "14027", 2271 | "14024", 2272 | "14022", 2273 | "14021", 2274 | "14019", 2275 | "14017", 2276 | "14014", 2277 | "14002", 2278 | "13999", 2279 | "13996", 2280 | "13990", 2281 | "13977", 2282 | "13976", 2283 | "13975", 2284 | "13972", 2285 | "13962", 2286 | "13961", 2287 | "13960", 2288 | "13956", 2289 | "13954", 2290 | "13950", 2291 | "13945", 2292 | "13941", 2293 | "13936", 2294 | "13934", 2295 | "13929", 2296 | "13926", 2297 | "13921", 2298 | "13919", 2299 | "13917", 2300 | "13916", 2301 | "13913", 2302 | "13910", 2303 | "13902", 2304 | "13898", 2305 | "13891", 2306 | "13890", 2307 | "13889", 2308 | "13880", 2309 | "13873", 2310 | "13872", 2311 | "13870", 2312 | "13869", 2313 | "13865", 2314 | "13861", 2315 | "13854", 2316 | "13845", 2317 | "13842", 2318 | "13832", 2319 | "13831", 2320 | "13827", 2321 | "13823", 2322 | "13817", 2323 | "13816", 2324 | "13812", 2325 | "13811", 2326 | "13810", 2327 | "13808", 2328 | "13789", 2329 | "13786", 2330 | "13782", 2331 | "13781", 2332 | "13771", 2333 | "13767", 2334 | "13755", 2335 | "13750", 2336 | "13748", 2337 | "13743", 2338 | "13742", 2339 | "13693", 2340 | "13692", 2341 | "13676", 2342 | "13673", 2343 | "13667", 2344 | "13664", 2345 | "13663", 2346 | "13656", 2347 | "13654", 2348 | "13652", 2349 | "13647", 2350 | "13644", 2351 | "13639", 2352 | "13638", 2353 | "13634", 2354 | "13630", 2355 | "13629", 2356 | "13623", 2357 | "13619", 2358 | "13617", 2359 | "13614", 2360 | "13603", 2361 | "13601", 2362 | "13599", 2363 | "13595", 2364 | "13594", 2365 | "13592", 2366 | "13583", 2367 | "13578", 2368 | "13577", 2369 | "13572", 2370 | "13560", 2371 | "13553", 2372 | "13552", 2373 | "13549", 2374 | "13544", 2375 | "13539", 2376 | "13536", 2377 | "13531", 2378 | "13528", 2379 | "13526", 2380 | "13523", 2381 | "13517", 2382 | "13504", 2383 | "13492", 2384 | "13483", 2385 | "13481", 2386 | "13475", 2387 | "13474", 2388 | "13470", 2389 | "13466", 2390 | "13457", 2391 | "13456", 2392 | "13441", 2393 | "13440", 2394 | "13433", 2395 | "13430", 2396 | "13424", 2397 | "13420", 2398 | "13418", 2399 | "13409", 2400 | "13404", 2401 | "13401", 2402 | "13398", 2403 | "13388", 2404 | "13386", 2405 | "13361", 2406 | "13360", 2407 | "13358", 2408 | "13352", 2409 | "13350", 2410 | "13340", 2411 | "13338", 2412 | "13335", 2413 | "13331", 2414 | "13330", 2415 | "13329", 2416 | "13328", 2417 | "13327", 2418 | "13326", 2419 | "13321", 2420 | "13311", 2421 | "13306", 2422 | "13295", 2423 | "13293", 2424 | "13291", 2425 | "13286", 2426 | "13285", 2427 | "13284", 2428 | "13282", 2429 | "13277", 2430 | "13275", 2431 | "13270", 2432 | "13263", 2433 | "13258", 2434 | "13251", 2435 | "13250", 2436 | "13247", 2437 | "13246", 2438 | "13244", 2439 | "13241", 2440 | "13237", 2441 | "13233", 2442 | "13231", 2443 | "13228", 2444 | "13224", 2445 | "13221", 2446 | "13215", 2447 | "13206", 2448 | "13187", 2449 | "13184", 2450 | "13167", 2451 | "13166", 2452 | "13162", 2453 | "13157", 2454 | "13155", 2455 | "13147", 2456 | "13099", 2457 | "13069", 2458 | "13059", 2459 | "13056", 2460 | "13049", 2461 | "13048", 2462 | "13033", 2463 | "13031", 2464 | "13028", 2465 | "13026", 2466 | "13024", 2467 | "13023", 2468 | "13016", 2469 | "13015", 2470 | "13013", 2471 | "13008", 2472 | "13001", 2473 | "12989", 2474 | "12983", 2475 | "12979", 2476 | "12977", 2477 | "12955", 2478 | "12953", 2479 | "12951", 2480 | "12950", 2481 | "12947", 2482 | "12939", 2483 | "12936", 2484 | "12933", 2485 | "12932", 2486 | "12926", 2487 | "12923", 2488 | "12922", 2489 | "12904", 2490 | "12895", 2491 | "12892", 2492 | "12890", 2493 | "12876", 2494 | "12873", 2495 | "12860", 2496 | "12857", 2497 | "12850", 2498 | "12849", 2499 | "12848", 2500 | "12845", 2501 | "12839", 2502 | "12838", 2503 | "12835", 2504 | "12831", 2505 | "12810", 2506 | "12797", 2507 | "12753", 2508 | "12744", 2509 | "12723", 2510 | "12714", 2511 | "12705", 2512 | "12691", 2513 | "12684", 2514 | "12682", 2515 | "12680", 2516 | "12678", 2517 | "12675", 2518 | "12671", 2519 | "12669", 2520 | "12663", 2521 | "12655", 2522 | "12650", 2523 | "12648", 2524 | "12643", 2525 | "12640", 2526 | "12636", 2527 | "12635", 2528 | "12633", 2529 | "12621", 2530 | "12616", 2531 | "12613", 2532 | "12609", 2533 | "12608", 2534 | "12603", 2535 | "12601", 2536 | "12600", 2537 | "12599", 2538 | "12594", 2539 | "12593", 2540 | "12588", 2541 | "12585", 2542 | "12584", 2543 | "12577", 2544 | "12571", 2545 | "12570", 2546 | "12565", 2547 | "12561", 2548 | "12559", 2549 | "12554", 2550 | "12540", 2551 | "12533", 2552 | "12519", 2553 | "12510", 2554 | "12501", 2555 | "12497", 2556 | "12492", 2557 | "12488", 2558 | "12487", 2559 | "12479", 2560 | "12463", 2561 | "12458", 2562 | "12451", 2563 | "12441", 2564 | "12420", 2565 | "12419", 2566 | "12411", 2567 | "12402", 2568 | "12401", 2569 | "12397", 2570 | "12391", 2571 | "12378", 2572 | "12363", 2573 | "12355", 2574 | "12352", 2575 | "12346", 2576 | "12325", 2577 | "12317", 2578 | "12316", 2579 | "12313", 2580 | "12306", 2581 | "12303", 2582 | "12293", 2583 | "12237", 2584 | "12232", 2585 | "12213", 2586 | "12131", 2587 | "12127", 2588 | "12107", 2589 | "12101", 2590 | "11783", 2591 | "11775", 2592 | "11697", 2593 | "11691", 2594 | "11664", 2595 | "11585", 2596 | "11582", 2597 | "11571", 2598 | "13717", 2599 | "13706", 2600 | "13704", 2601 | "13198", 2602 | "13196", 2603 | "12351", 2604 | "12336", 2605 | "12279", 2606 | ] 2607 | -------------------------------------------------------------------------------- /wanda/sources/extractor.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os 3 | import random 4 | import re 5 | 6 | import cloudscraper # type: ignore 7 | import filetype # type: ignore 8 | from PIL import Image # type: ignore 9 | 10 | from wanda.sources.earthview_ids import earthview_ids 11 | from wanda.sources.generator.gradient1 import linear_gradient 12 | from wanda.sources.generator.gradient2 import bilinear_gradient 13 | from wanda.sources.generator.honeycomb import honeycomb 14 | from wanda.sources.generator.tiles import tiles 15 | from wanda.utils.common_utils import blank, get, ok, contains, get_dl_path 16 | from wanda.utils.image_utils import screen_orientation, good_size 17 | from wanda.utils.os_utils import size 18 | 19 | user_agent = {"User-Agent": "git.io/wanda"} 20 | 21 | 22 | def no_results(): 23 | print("No results found.") 24 | print("• Try another source or term") 25 | print("• Try again at a later time") 26 | exit(1) 27 | 28 | 29 | def fourchan(search=None): 30 | if blank(search): 31 | search = "" 32 | board = "wg" 33 | elif "@" not in search: 34 | search = f"{search.lower()}" if search else "" 35 | board = "wg" 36 | else: 37 | board = search.split("@")[1] 38 | search = search.split("@")[0].lower() 39 | 40 | api = f"https://archive.palanq.win/_/api/chan/search/?boards={board}&subject={search.lower()}" 41 | response = get(api).json() 42 | no_results() if "error" in response else ok() 43 | posts = list( 44 | filter(lambda p: "media" in p and "nimages" in p, response["0"]["posts"]) 45 | ) 46 | ok() if posts else no_results() 47 | post = random.choice(posts) 48 | thread = post["thread_num"] 49 | board = post["board"]["shortname"] 50 | api = f"https://archive.palanq.win/_/api/chan/thread/?board={board}&num={thread}" 51 | posts = get(api).json()[thread]["posts"] 52 | ok() if posts else no_results() 53 | post = random.choice(list(filter(lambda p: "media" in posts[p], posts))) 54 | if posts[post]: 55 | return posts[post]["media"]["media_link"] 56 | return no_results() 57 | 58 | 59 | def suggested_subreddits(): 60 | if screen_orientation() == "portrait": 61 | return "mobilewallpaper+amoledbackgrounds+verticalwallpapers" 62 | return "wallpaper+wallpapers+minimalwallpaper" 63 | 64 | 65 | def reddit_gallery(url): 66 | if "/gallery/" not in url: 67 | return 68 | else: 69 | url = url.replace("/gallery/", "/comments/") 70 | images = get(f"{url}.json").json()[0]["data"]["children"][0]["data"][ 71 | "media_metadata" 72 | ] 73 | ids = images.keys() 74 | return list( 75 | map(lambda i: f'https://i.redd.it/{i}.{images[i]["m"].split("/")[1]}', ids) 76 | ) 77 | 78 | 79 | def is_imgur_gallery(url): 80 | return contains(url, False, ["imgur.com/a", "imgur.com/gallery"]) 81 | 82 | 83 | def reddit_search(sub, search=None, extra=""): 84 | base = "https://old.reddit.com/r/" 85 | if not search: 86 | return f"{base}{sub}.json?{extra}" 87 | common_param = ( 88 | f"&restrict_sr=on&sort=relevance&t=all&sort=top&limit=100&type=link{extra}" 89 | ) 90 | search_api = "/search.json?q=" 91 | return f"{base}{sub}{search_api}{search}{common_param}" 92 | 93 | 94 | def reddit_compare_image_size(title): 95 | sr = re.search(r"\d+x\d+", title) 96 | if sr: 97 | w = int(sr.group().split("x")[0]) >= int(size()[0]) 98 | h = int(sr.group().split("x")[1]) >= int(size()[1]) 99 | return w and h 100 | return screen_orientation() == "portrait" or False 101 | 102 | 103 | def reddit(search=None, subreddits=suggested_subreddits()): 104 | if search and "@" in search: 105 | subreddits = search.split("@")[1] 106 | search = search.split("@")[0] 107 | api = reddit_search(subreddits, search) 108 | posts = get(api).json()["data"]["children"] 109 | image_urls = [ 110 | "reddit.com/gallery", 111 | "imgur.com/a", 112 | "imgur.com/gallery", 113 | "i.redd.it", 114 | "i.imgur", 115 | ] 116 | posts = list( 117 | filter( 118 | lambda p: contains(p["data"]["url"], False, image_urls) 119 | and reddit_compare_image_size(p["data"]["title"]), 120 | posts, 121 | ) 122 | ) 123 | if not posts: 124 | no_results() 125 | url = random.choice(posts)["data"]["url"] 126 | if "reddit.com/gallery" in url: 127 | return random.choice(reddit_gallery(url)) 128 | elif is_imgur_gallery(url): 129 | return imgur(search=os.path.basename(url)) 130 | elif contains(url, False, ["i.redd.it", "i.imgur", ".png", ".jpg"]): 131 | return url 132 | else: 133 | no_results() 134 | 135 | 136 | def picsum(search=None): 137 | w, h = size() 138 | if blank(search): 139 | api = f"https://picsum.photos/{w}/{h}" 140 | else: 141 | api = f"https://picsum.photos/seed/{search}/{w}/{h}" 142 | return get(api).url 143 | 144 | 145 | def imgur(alt="rimgo.eu.projectsegfau.lt", search=None): 146 | if search: 147 | from lxml import html 148 | tree = html.fromstring(get(f"https://{alt}/a/{search}").content) 149 | images = tree.xpath("//main//img[@loading]") 150 | return f"https://{alt}{random.choice(images).attrib['src']}" if images else no_results() 151 | return no_results() 152 | 153 | 154 | def artstation_prints(search=None): 155 | scraper = cloudscraper.create_scraper() 156 | orientation = "portrait" if screen_orientation() == "portrait" else "landscape" 157 | search = search or "" 158 | api = ( 159 | f"https://www.artstation.com/api/v2/prints/public/printed_products.json?page=1&per_page=30" 160 | f"&orientation={orientation}&sort=trending&visibility=profile&variant_filter=price_limits_per_type" 161 | f"&q={search}" 162 | ) 163 | response = scraper.get(api, headers=user_agent).json()["data"] 164 | return ( 165 | random.choice(response)["print_type_variants"][0]["image_urls"][0]["url"] 166 | if response 167 | else no_results() 168 | ) 169 | 170 | 171 | def artstation_artist(search=None): 172 | if blank(search): 173 | print("Please provide an artist id") 174 | exit(1) 175 | response = get(f"https://www.artstation.com/users/{search}/hovercard.json") 176 | no_results() if response.status_code != 200 else ok() 177 | projects = get(f"https://www.artstation.com/users/{search}/projects.json").json() 178 | artwork = random.choice(projects["data"])["permalink"].split("/")[-1] 179 | return get(f"https://www.artstation.com/projects/{artwork}.json").json()["assets"][ 180 | 0 181 | ]["image_url"] 182 | 183 | 184 | def artstation_any(search=None): 185 | scraper = cloudscraper.create_scraper() 186 | search = "nature" if blank(search) else search 187 | body = { 188 | "query": search, 189 | "page": 1, 190 | "per_page": 50, 191 | "sorting": "relevance", 192 | "pro_first": "1", 193 | "filters": "[]", 194 | "additional_fields": [], 195 | } 196 | api = "https://www.artstation.com/api/v2/search/projects.json" 197 | headers = { 198 | "User-Agent": user_agent["User-Agent"], 199 | "Host": "www.artstation.com", 200 | "Content-Type": "application/json", 201 | } 202 | assets = scraper.get(api, json=body, headers=headers).json()["data"] 203 | 204 | no_results() if isinstance(assets, str) else ok() 205 | # noinspection PyTypeChecker 206 | hash_id = random.choice(assets)["hash_id"] if assets else no_results() 207 | 208 | api = f"https://www.artstation.com/projects/{hash_id}.json" 209 | assets = scraper.get(api, json=body, headers=headers).json()["assets"] 210 | random.shuffle(assets) if assets else no_results() 211 | for asset in assets: 212 | h = asset["height"] 213 | w = asset["width"] 214 | if good_size(w, h): 215 | return asset["image_url"] 216 | return random.choice(assets)["image_url"] 217 | 218 | 219 | def local(path): 220 | if blank(path): 221 | print("Please specify path to images") 222 | exit(1) 223 | if path and not path.endswith("/"): 224 | path = f"{path}/" 225 | if os.path.exists(path): 226 | return path + random.choice( 227 | list( 228 | filter( 229 | lambda f: os.path.isfile(path + f) 230 | and filetype.guess(path + f).MIME.startswith("image"), 231 | os.listdir(path), 232 | ) 233 | ) 234 | ) 235 | return no_results() 236 | 237 | 238 | def waifuim(search=None): 239 | orientation = "PORTRAIT" if screen_orientation() == "portrait" else "LANDSCAPE" 240 | accept = f"&included_tags={search}" if search else "" 241 | reject = "" 242 | if search and "-" in search: 243 | accept = f"&selected_tags={search.split('-')[0]}" 244 | reject = f"&excluded_tags={search.split('-')[1]}" 245 | api = ( 246 | f"https://api.waifu.im/search/?gif=false&is_nsfw=false" 247 | f"&orientation={orientation}{accept}{reject}" 248 | ) 249 | response = get(api).json() 250 | no_results() if "detail" in response else ok() 251 | return response["images"][0]["url"] 252 | 253 | 254 | def musicbrainz(search=None): 255 | import musicbrainzngs as mb # type: ignore 256 | 257 | if blank(search): 258 | print("Please enter [artist]-[album]") 259 | exit(1) 260 | mb.set_useragent("wanda", "*", user_agent["User-Agent"]) 261 | [artist, album] = search.split("-") 262 | try: 263 | albums = mb.search_releases(album, artist=artist) 264 | ok() if albums else no_results() 265 | if not albums["release-list"]: 266 | raise mb.MusicBrainzError 267 | album_id = albums["release-list"][0]["release-group"]["id"] 268 | cover = mb.get_release_group_image_front(album_id) 269 | path = get_dl_path() 270 | with open(path, "wb") as f: 271 | f.write(cover) 272 | ext = filetype.guess(path).EXTENSION 273 | os.rename(path, f"{path}.{ext}") 274 | return f"{path}.{ext}" 275 | except mb.MusicBrainzError: 276 | no_results() 277 | 278 | 279 | def wallhaven(search=None): 280 | api = "https://wallhaven.cc/api/v1/search?sorting=random" 281 | ratios = "portrait" if screen_orientation() == "portrait" else "landscape" 282 | response = get(f"{api}&ratios={ratios}&q={search or ''}").json()["data"] 283 | return response[0]["path"] if response else no_results() 284 | 285 | 286 | def earthview(_): 287 | # https://chromewebstore.google.com/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh 288 | # 3.1.0 289 | url = f"https://www.gstatic.com/prettyearth/assets/data/v3/{random.choice(earthview_ids)}.json" 290 | response = get(url) 291 | data = response.json() 292 | image_data = data.get("dataUri", "") 293 | 294 | if image_data: 295 | image_data = image_data.split(",")[-1] 296 | image_bytes = base64.b64decode(image_data) 297 | filename = get_dl_path("jpg") 298 | with open(filename, "wb") as f: 299 | f.write(image_bytes) 300 | 301 | if screen_orientation() == "portrait": 302 | image = Image.open(filename) 303 | rotated_image = image.rotate(90, expand=True) 304 | rotated_image.save(filename) 305 | 306 | return filename 307 | return no_results() 308 | 309 | 310 | def generate(term): 311 | path = get_dl_path("png") 312 | w, h = size() 313 | if term == "linear" or term == "gl": 314 | image = linear_gradient(w, h) 315 | elif term == "bilinear" or term == "gb": 316 | image = bilinear_gradient(w, h) 317 | elif term == "honeycomb" or term == "h": 318 | image = honeycomb(w, h) 319 | elif term == "tiles" or term == "t": 320 | image = tiles(w, h) 321 | else: 322 | term = random.choice(["gl", "gb", "h", "t"]) 323 | return generate(term) 324 | 325 | image.save(path) 326 | return path 327 | -------------------------------------------------------------------------------- /wanda/sources/generator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/wanda/sources/generator/__init__.py -------------------------------------------------------------------------------- /wanda/sources/generator/gradient1.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw 2 | 3 | from wanda.sources.generator.scheme import generate_random_color 4 | from wanda.utils.common_utils import coin_toss 5 | 6 | 7 | def linear_gradient(width, height): 8 | image = Image.new("RGB", (width, height), "white") 9 | draw = ImageDraw.Draw(image) 10 | 11 | start_color = generate_random_color(True) 12 | end_color = generate_random_color(True) 13 | 14 | if coin_toss(): 15 | for x in range(width): 16 | r = int(start_color[0] * (1 - x / width) + end_color[0] * (x / width)) 17 | g = int(start_color[1] * (1 - x / width) + end_color[1] * (x / width)) 18 | b = int(start_color[2] * (1 - x / width) + end_color[2] * (x / width)) 19 | for y in range(height): 20 | draw.point((x, y), fill=(r, g, b)) 21 | else: 22 | for y in range(height): 23 | r = int(start_color[0] * (1 - y / height) + end_color[0] * (y / height)) 24 | g = int(start_color[1] * (1 - y / height) + end_color[1] * (y / height)) 25 | b = int(start_color[2] * (1 - y / height) + end_color[2] * (y / height)) 26 | for x in range(width): 27 | draw.point((x, y), fill=(r, g, b)) 28 | 29 | return image 30 | -------------------------------------------------------------------------------- /wanda/sources/generator/gradient2.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw 2 | 3 | from wanda.sources.generator.scheme import generate_random_color 4 | 5 | 6 | def bilinear_gradient(width, height): 7 | image = Image.new("RGB", (width, height), "white") 8 | draw = ImageDraw.Draw(image) 9 | 10 | start_color = generate_random_color(True) 11 | end_color = generate_random_color(True) 12 | 13 | for y in range(height): 14 | for x in range(width): 15 | r = int(start_color[0] * (1 - x / width) + end_color[0] * (x / width)) 16 | g = int(start_color[1] * (1 - y / height) + end_color[1] * (y / height)) 17 | b = int(start_color[2] * (1 - x / width) + end_color[2] * (x / width)) 18 | draw.point((x, y), fill=(r, g, b)) 19 | 20 | return image 21 | -------------------------------------------------------------------------------- /wanda/sources/generator/honeycomb.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | 4 | from PIL import Image, ImageDraw 5 | 6 | from wanda.sources.generator.scheme import get_color_scheme, invalid_number 7 | 8 | 9 | def draw_hexagon(draw, center, size, color, rotation=0): 10 | corners = [] 11 | for i in range(6): 12 | angle_deg = 60 * i + rotation 13 | angle_rad = math.pi / 180 * angle_deg 14 | x = center[0] + size * math.cos(angle_rad) 15 | y = center[1] + size * math.sin(angle_rad) 16 | corners.append((x, y)) 17 | draw.polygon(corners, fill=color, outline=color) 18 | 19 | 20 | def honeycomb( 21 | width, 22 | height, 23 | count=None, 24 | hex_size=None, 25 | horizontal_spacing=None, 26 | vertical_spacing=None, 27 | ): 28 | if invalid_number(count): 29 | count = 4 30 | if invalid_number(hex_size): 31 | hex_size = 30 32 | if invalid_number(horizontal_spacing): 33 | horizontal_spacing = 2 * hex_size 34 | if invalid_number(vertical_spacing): 35 | vertical_spacing = math.sqrt(3) * hex_size 36 | 37 | colors = get_color_scheme(count) 38 | background_color = colors[0] 39 | image = Image.new("RGB", (width, height), background_color) 40 | draw = ImageDraw.Draw(image) 41 | 42 | rows = int(height / vertical_spacing) + 2 43 | cols = int(width / horizontal_spacing) + 1 44 | 45 | for row in range(rows): 46 | for col in range(cols): 47 | x = col * horizontal_spacing + (row % 2) * (horizontal_spacing / 2) 48 | y = row * vertical_spacing 49 | color = random.choice(colors[1:]) 50 | draw_hexagon(draw, (x, y), hex_size, color, rotation=30) 51 | 52 | # Save the image 53 | return image 54 | -------------------------------------------------------------------------------- /wanda/sources/generator/scheme.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import requests 4 | 5 | from wanda.utils.common_utils import coin_toss 6 | 7 | 8 | def generate_random_color(as_rgb=False): 9 | while True: 10 | r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) 11 | if r > 200 and g < 150 < b: 12 | continue 13 | max_val = max(r, g, b) 14 | min_val = min(r, g, b) 15 | if max_val == 0: 16 | saturation = 0 17 | else: 18 | saturation = 1 - min_val / max_val 19 | if saturation < 1.0: 20 | if as_rgb: 21 | return r, g, b 22 | return "#{:02x}{:02x}{:02x}".format(r, g, b) 23 | 24 | 25 | def rearrange_colors(colors_list): 26 | sorted_colors = sorted(colors_list, key=lambda color: sum(color)) 27 | if coin_toss: 28 | sorted_colors.reverse() 29 | return sorted_colors 30 | 31 | 32 | def get_color_scheme(count=5): 33 | modes = ["monochrome", "monochrome-dark", "monochrome-light"] 34 | 35 | random_mode = random.choice(modes) 36 | random_hex = generate_random_color() 37 | url = "https://www.thecolorapi.com/scheme" 38 | params = {"hex": random_hex, "mode": random_mode, "count": count} 39 | try: 40 | response = requests.get(url, params=params) 41 | if response.status_code == 200: 42 | response_data = response.json() 43 | colors_list = [ 44 | (color["rgb"]["r"], color["rgb"]["g"], color["rgb"]["b"]) 45 | for color in response_data["colors"] 46 | ] 47 | return rearrange_colors(colors_list) 48 | else: 49 | colors_list = [(generate_random_color(True)) for _ in range(count)] 50 | return rearrange_colors(colors_list) 51 | except: 52 | colors_list = [(generate_random_color(True)) for _ in range(count)] 53 | return rearrange_colors(colors_list) 54 | 55 | 56 | def invalid_number(maybe_number): 57 | return not maybe_number or not (isinstance(maybe_number, int)) 58 | -------------------------------------------------------------------------------- /wanda/sources/generator/tiles.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw 2 | 3 | from wanda.sources.generator.scheme import get_color_scheme, invalid_number 4 | 5 | 6 | def tiles(width, height, tile_size=None, num_colors=None): 7 | if invalid_number(tile_size): 8 | tile_size = 50 9 | if invalid_number(num_colors): 10 | num_colors = 5 11 | 12 | colors = get_color_scheme(num_colors) 13 | texture = Image.new("RGB", (width, height), "white") 14 | draw = ImageDraw.Draw(texture) 15 | 16 | for x in range(0, width, tile_size): 17 | for y in range(0, height, tile_size): 18 | color = colors[(x // tile_size + y // tile_size) % len(colors)] 19 | draw.rectangle((x, y, x + tile_size, y + tile_size), fill=color) 20 | 21 | # Save the generated texture 22 | return texture 23 | -------------------------------------------------------------------------------- /wanda/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksh-b/wanda/dea971a30a82886905e647120d13096a49f24dd0/wanda/utils/__init__.py -------------------------------------------------------------------------------- /wanda/utils/common_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import subprocess 4 | import time 5 | 6 | import appdirs 7 | import cloudscraper # type: ignore 8 | import filetype # type: ignore 9 | 10 | folder = appdirs.user_cache_dir("wanda") 11 | 12 | 13 | def command(string: str) -> str: 14 | return subprocess.check_output(string.split(" ")).decode().strip() 15 | 16 | 17 | def get_dl_path(ext=""): 18 | path = os.path.normpath(f"{folder}/wanda_{int(time.time())}.{ext}") 19 | if not os.path.exists(folder): 20 | os.mkdir(folder) 21 | empty_download_folder() 22 | return path 23 | 24 | 25 | def empty_download_folder(): 26 | import glob 27 | 28 | files = glob.glob(f"{folder}/*") 29 | for f in files: 30 | os.remove(f) 31 | 32 | 33 | def download(path, url): 34 | with open(path, "wb") as f: 35 | f.write(get(url).content) 36 | ext = filetype.guess(path).EXTENSION 37 | os.rename(path, f"{path}.{ext}") 38 | return f"{path}.{ext}" 39 | 40 | 41 | def get(url): 42 | scraper = cloudscraper.create_scraper() 43 | response = scraper.get( 44 | url, 45 | headers={"Accept": "image/avif,image/webp,*/*", "User-Agent": "git.io/wanda"}, 46 | timeout=10, 47 | allow_redirects=True, 48 | ) 49 | if response.status_code != 200: 50 | from http.client import responses 51 | 52 | print(f"Got status code [{responses[response.status_code]}] from {url}") 53 | exit(1) 54 | return response 55 | 56 | 57 | def blank(search): 58 | return not search or search == "" 59 | 60 | 61 | def contains(word: str, match_all: bool, desired: list) -> bool: 62 | matches = list( 63 | map(lambda w: w not in word if w.startswith("!") else w in word, desired) 64 | ) 65 | if not match_all: 66 | return True in matches 67 | return set(matches) == {True} 68 | 69 | 70 | def is_connected(): 71 | # noinspection PyBroadException 72 | try: 73 | result = get("https://detectportal.firefox.com/success.txt") 74 | return result.text.strip() == "success" 75 | except Exception: 76 | return False 77 | 78 | 79 | def coin_toss(): 80 | return bool(random.getrandbits(1)) 81 | 82 | 83 | # do nothing 84 | def ok(): 85 | pass 86 | -------------------------------------------------------------------------------- /wanda/utils/image_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from wanda.utils.common_utils import get_dl_path, download 4 | from wanda.utils.os_utils import ( 5 | size, 6 | set_wp_android, 7 | set_wp_linux, 8 | set_wp_win, 9 | is_android, 10 | ) 11 | 12 | 13 | def screen_orientation(): 14 | return "landscape" if size()[0] > size()[1] else "portrait" 15 | 16 | 17 | def image_orientation(image): 18 | return "landscape" if image.width > image.height else "portrait" 19 | 20 | 21 | def good_size(w, h): 22 | return (screen_orientation() == "portrait" and w < h) or ( 23 | screen_orientation() == "landscape" and w > h 24 | ) 25 | 26 | 27 | # get dominant color from image 28 | def dominant_color(wallpaper_path): 29 | from colorthief import ColorThief # type: ignore 30 | 31 | color_thief = ColorThief(wallpaper_path) 32 | return color_thief.get_color(quality=1) 33 | 34 | 35 | def fit(wallpaper_path): 36 | from PIL import Image 37 | 38 | wp = Image.open(wallpaper_path) 39 | scr_width, scr_height = size() 40 | 41 | # if image is squarish (like album art) 42 | if 95 < int(wp.width / wp.height) * 100 < 105: 43 | bg = Image.new("RGB", (size()), dominant_color(wallpaper_path)) 44 | percentage = 0 45 | if screen_orientation() == "portrait" and wp.width > scr_width: 46 | percentage = wp.width / scr_width 47 | elif screen_orientation() == "landscape" and wp.height > scr_height: 48 | percentage = wp.height / scr_height 49 | if percentage != 0: 50 | print("Fitting // squarish image") 51 | resized_dimensions = ( 52 | int(wp.width / percentage), 53 | int(wp.height / percentage), 54 | ) 55 | resized = wp.resize(resized_dimensions) 56 | x1 = int(scr_width / 2) - int(resized.width / 2) 57 | y1 = int(scr_height / 2) - int(resized.height / 2) 58 | bg.paste(resized, (x1, y1)) 59 | bg.save(wallpaper_path) 60 | 61 | # image smaller than screen 62 | elif wp.height < scr_height and wp.width < scr_width: 63 | print("Fitting // image smaller than screen") 64 | bg = Image.new("RGB", (size()), dominant_color(wallpaper_path)) 65 | x1 = int(scr_width / 2) - int(wp.width / 2) 66 | y1 = int(scr_height / 2) - int(wp.height / 2) 67 | bg.paste(wp, (x1, y1)) 68 | bg.save(wallpaper_path) 69 | 70 | # image == portrait but screen == landscape 71 | elif image_orientation(wp) == "portrait" and screen_orientation() == "landscape": 72 | print("Fitting // image is portrait but screen is landscape") 73 | bg = Image.new("RGB", (size()), dominant_color(wallpaper_path)) 74 | percentage = wp.height / scr_height 75 | resized_dimensions = ( 76 | int(wp.width / percentage), 77 | int(wp.height / percentage), 78 | ) 79 | resized = wp.resize(resized_dimensions) 80 | x1 = int(scr_width / 2) - int(resized.width / 2) 81 | y1 = 0 82 | bg.paste(resized, (x1, y1)) 83 | bg.save(wallpaper_path) 84 | 85 | # image == landscape but screen == portrait 86 | elif image_orientation(wp) == "landscape" and screen_orientation() == "portrait": 87 | print("Fitting // image is landscape but screen is portrait") 88 | bg = Image.new("RGB", (size()), dominant_color(wallpaper_path)) 89 | percentage = wp.width / scr_width 90 | resized_dimensions = ( 91 | int(wp.width / percentage), 92 | int(wp.height / percentage), 93 | ) 94 | resized = wp.resize(resized_dimensions) 95 | x1 = 0 96 | y1 = int(scr_height / 2) - int(resized.height / 2) 97 | bg.paste(resized, (x1, y1)) 98 | bg.save(wallpaper_path) 99 | 100 | return wallpaper_path 101 | 102 | 103 | def set_wp(url: str, home=True, lock=True, fitwp=False): 104 | # print selected wallpaper url 105 | print(url) 106 | 107 | # download wallpaper 108 | if url.replace("http://", "https://").startswith("https://"): 109 | path = get_dl_path() 110 | path = download(path, url) 111 | elif os.path.exists(url): 112 | path = url 113 | else: 114 | print("Invalid url/path") 115 | return 1 116 | 117 | # fit wallpaper to screen if orientation mismatch 118 | if fitwp: 119 | path = fit(path) 120 | 121 | # set wallpaper 122 | import platform 123 | 124 | if is_android(): 125 | set_wp_android(path, home, lock) 126 | elif platform.system() == "Linux": 127 | set_wp_linux(path) 128 | elif platform.system() == "Windows": 129 | set_wp_win(path) 130 | else: 131 | print("Platform not supported") 132 | exit(1) 133 | -------------------------------------------------------------------------------- /wanda/utils/os_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | from wanda.utils.common_utils import command, blank, contains 5 | 6 | 7 | def program_exists(program): 8 | return ( 9 | subprocess.call( 10 | ["which", program], 11 | stdout=subprocess.DEVNULL, 12 | stderr=subprocess.DEVNULL, 13 | ) 14 | == 0 15 | ) 16 | 17 | 18 | def set_wp_win(path): 19 | import ctypes 20 | 21 | ctypes.windll.user32.SystemParametersInfoW(20, 0, path, 0) 22 | 23 | 24 | def set_wp_linux(path): 25 | if not os.environ.get("DESKTOP_SESSION"): 26 | setter = "feh --bg-scale" 27 | elif os.environ.get("SWAYSOCK"): 28 | setter = "eval ogurictl output '*' --image" 29 | elif os.environ.get("DESKTOP_SESSION").lower == "mate": 30 | setter = "gsettings set org.mate.background picture-filename" 31 | elif contains( 32 | os.environ.get("DESKTOP_SESSION").lower(), False, ["xfce", "xubuntu"] 33 | ): 34 | if program_exists("xfce4-set-wallpaper"): 35 | setter = "xfce4-set-wallpaper" 36 | else: 37 | screens = command("xfconf-query --channel xfce4-desktop -l").split("\n") 38 | screens = list(filter(lambda it: "/workspace" in it, screens)) 39 | for screen in screens: 40 | setter = ( 41 | f"xfconf-query --channel xfce4-desktop --property {screen} --set " 42 | ) 43 | command(f"{setter} {path}") 44 | return 45 | elif os.environ.get("DESKTOP_SESSION").lower() == "lxde": 46 | setter = "pcmanfm --wallpaper-mode=screen --set-wallpaper" 47 | elif os.environ.get("DESKTOP_SESSION").lower() == "lxqt": 48 | setter = "pcmanfm-qt --set-wallpaper" 49 | elif contains( 50 | os.environ.get("DESKTOP_SESSION").lower(), False, ["plasma", "neon", "kde"] 51 | ): 52 | return os.system( 53 | 'qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "\n' 54 | + "var allDesktops = desktops();\n" 55 | + "print (allDesktops);\n" 56 | + "for (i=0;i= 1: 34 | print("Wallhaven advanced usage:") 35 | print("For full list of parameters, go to https://wallhaven.cc/help/api#search") 36 | print( 37 | "example: wanda -sw -tcar,lamborghini&colors=cc3333&categories=111&purity=100" 38 | ) 39 | 40 | if level >= 2: 41 | print("\033[33mShort codes:") 42 | print(json.dumps(shortcodes(), indent=2).strip("{}").replace('"', "")) 43 | 44 | 45 | def parser(): 46 | parser_ = argparse.ArgumentParser(description="Set wallpapers") 47 | 48 | parser_.add_argument( 49 | "-s", 50 | metavar="source", 51 | type=str, 52 | default="picsum", 53 | help="Source for wallpaper. -u for all supported sources", 54 | required=False, 55 | ) 56 | parser_.add_argument( 57 | "-t", 58 | metavar="term", 59 | type=str, 60 | default=None, 61 | help="Search term. -u for more help", 62 | required=False, 63 | ) 64 | parser_.add_argument( 65 | "-d", 66 | metavar="download", 67 | nargs="?", 68 | const=str(Path.home()), 69 | help="Copy last downloaded wallpaper to home directory or given path", 70 | ) 71 | parser_.add_argument( 72 | "-u", 73 | metavar="usage", 74 | help="Supported sources and their usage", 75 | required=False, 76 | action="store_const", 77 | const=None, 78 | ) 79 | parser_.add_argument( 80 | "-f", 81 | help="Fit wallpaper to screen if screen and wallpaper orientation mismatch", 82 | required=False, 83 | action="store_true", 84 | ) 85 | if os_utils.is_android(): 86 | parser_.add_argument( 87 | "-o", 88 | help="Set wallpaper on homescreen.", 89 | required=False, 90 | action="store_true", 91 | ) 92 | parser_.add_argument( 93 | "-l", 94 | help="Set wallpaper on lockscreen.", 95 | required=False, 96 | action="store_true", 97 | ) 98 | return parser_ 99 | 100 | 101 | def run(): 102 | args = parser().parse_args() 103 | if "-u" in sys.argv: 104 | usage(2) 105 | exit(0) 106 | if "-v" in sys.argv: 107 | print(args.v) 108 | exit(0) 109 | if "-d" in sys.argv: 110 | for src_file in Path(folder).glob("wanda_*.*"): 111 | import shutil 112 | 113 | shutil.copy(src_file, args.d) 114 | print(f"Copied wallpaper to {args.d}") 115 | exit(0) 116 | 117 | source = args.s 118 | term = args.t 119 | home = True 120 | lock = True 121 | fitwp = False 122 | if "-l" in sys.argv and args.l: 123 | home = False 124 | if "-h" in sys.argv and args.h: 125 | lock = False 126 | if "-f" in sys.argv and source_map(source) not in ("e", "earthview"): 127 | fitwp = True 128 | if source_map(source) != "local" and not common_utils.is_connected(): 129 | print("Please check your internet connection and try again") 130 | exit(1) 131 | if source_map(source) == "fourchan": 132 | wp = extractor.fourchan(term) 133 | elif source_map(source) == "generate": 134 | wp = extractor.generate(term) 135 | elif source_map(source) == "reddit": 136 | wp = extractor.reddit(term) 137 | elif source_map(source) == "picsum": 138 | wp = extractor.picsum(term) 139 | elif source_map(source) == "imgur": 140 | wp = extractor.imgur(term) 141 | elif source_map(source) == "artstation_prints": 142 | wp = extractor.artstation_prints(term) 143 | elif source_map(source) == "artstation_artist": 144 | wp = extractor.artstation_artist(term) 145 | elif source_map(source) == "artstation_any": 146 | wp = extractor.artstation_any(term) 147 | elif source_map(source) == "local": 148 | wp = extractor.local(term) 149 | elif source_map(source) == "waifuim": 150 | wp = extractor.waifuim(term) 151 | elif source_map(source) == "musicbrainz": 152 | wp = extractor.musicbrainz(term) 153 | elif source_map(source) == "wallhaven": 154 | wp = extractor.wallhaven(term) 155 | elif source_map(source) == "earthview": 156 | wp = extractor.earthview(term) 157 | else: 158 | print(f"Unknown Source: {source}. Using picsum.") 159 | wp = extractor.picsum(term) 160 | image_utils.set_wp(wp, home, lock, fitwp) 161 | return 0 162 | 163 | 164 | def shortcodes(): 165 | return { 166 | "4": "fourchan", 167 | "a": "artstation_any", 168 | "aa": "artstation_artist", 169 | "ap": "artstation_prints", 170 | "e": "earthview", 171 | "g": "generate", 172 | "i": "imgur", 173 | "l": "local", 174 | "m": "musicbrainz", 175 | "p": "picsum", 176 | "r": "reddit", 177 | "wi": "waifuim", 178 | "w": "wallhaven", 179 | } 180 | 181 | 182 | def source_map(shortcode): 183 | return shortcodes().get(shortcode, shortcode) 184 | 185 | 186 | if __name__ == "__main__": 187 | sys.exit(run()) 188 | --------------------------------------------------------------------------------