├── .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 | [](https://pypi.org/project/wanda/)
5 | [](https://pypistats.org/packages/wanda)
6 | [](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 |
--------------------------------------------------------------------------------