├── .appveyor.yml ├── .flake8 ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── MANIFEST.in ├── README.md ├── RELEASING.md ├── UNLICENSE ├── pyproject.toml ├── pytest.ini ├── requirements-dev.txt ├── setup.py ├── tests ├── httpcache │ ├── 07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854 │ ├── 08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264 │ ├── 0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892 │ ├── 120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6 │ ├── 19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1 │ ├── 1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f │ ├── 234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b │ ├── 26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00 │ ├── 28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a │ ├── 2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7 │ ├── 33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd │ ├── 376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52 │ ├── 3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4 │ ├── 3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172 │ ├── 3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f │ ├── 409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6 │ ├── 440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f │ ├── 44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054 │ ├── 45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91 │ ├── 4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36 │ ├── 4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194 │ ├── 4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524 │ ├── 4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19 │ ├── 4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0 │ ├── 4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3 │ ├── 52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0 │ ├── 5a6d8f221f3c375f3b0fd8e89773a859fb4301dab5f53bc9d34d8e33bbc431dc │ ├── 5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26 │ ├── 6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72 │ ├── 6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885 │ ├── 6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8 │ ├── 7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742 │ ├── 7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60 │ ├── 85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55 │ ├── 89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf │ ├── 91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7 │ ├── 923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c │ ├── 954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b │ ├── 9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9 │ ├── 9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216 │ ├── 9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766 │ ├── 9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03 │ ├── a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511 │ ├── a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd │ ├── b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d │ ├── bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745 │ ├── c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b │ ├── c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4 │ ├── cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088 │ ├── cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7 │ ├── ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3 │ ├── cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735 │ ├── d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a │ ├── d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96 │ ├── d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd │ ├── e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948 │ ├── e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea │ ├── e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373 │ ├── e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714 │ ├── e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4 │ ├── e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791 │ ├── ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e │ ├── f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51 │ ├── f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c │ ├── f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761 │ ├── f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c │ ├── f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d │ └── f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5 ├── httpcache_py2 │ ├── 07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854 │ ├── 08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264 │ ├── 0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892 │ ├── 120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6 │ ├── 19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1 │ ├── 1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f │ ├── 234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b │ ├── 26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00 │ ├── 28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a │ ├── 2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7 │ ├── 33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd │ ├── 376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52 │ ├── 3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4 │ ├── 3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172 │ ├── 3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f │ ├── 409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6 │ ├── 440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f │ ├── 44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054 │ ├── 45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91 │ ├── 4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36 │ ├── 4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194 │ ├── 4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524 │ ├── 4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19 │ ├── 4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0 │ ├── 4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3 │ ├── 52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0 │ ├── 5a6d8f221f3c375f3b0fd8e89773a859fb4301dab5f53bc9d34d8e33bbc431dc │ ├── 5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26 │ ├── 6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72 │ ├── 6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885 │ ├── 6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8 │ ├── 7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742 │ ├── 7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60 │ ├── 85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55 │ ├── 89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf │ ├── 91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7 │ ├── 923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c │ ├── 954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b │ ├── 9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9 │ ├── 9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216 │ ├── 9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766 │ ├── 9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03 │ ├── a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511 │ ├── a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd │ ├── b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d │ ├── bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745 │ ├── c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b │ ├── c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4 │ ├── cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088 │ ├── cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7 │ ├── ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3 │ ├── cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735 │ ├── d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a │ ├── d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96 │ ├── d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd │ ├── e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948 │ ├── e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea │ ├── e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373 │ ├── e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714 │ ├── e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4 │ ├── e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791 │ ├── ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e │ ├── f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51 │ ├── f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c │ ├── f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761 │ ├── f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c │ ├── f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d │ └── f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5 └── test_tvdb_api.py └── tvdb_api.py /.appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | 3 | matrix: 4 | # http://www.appveyor.com/docs/installed-software#python 5 | 6 | - PYTHON: C:\Python26 7 | - PYTHON: C:\Python26-x64 8 | - PYTHON: C:\Python27 9 | - PYTHON: C:\Python27-x64 10 | - PYTHON: C:\Python33 11 | - PYTHON: C:\Python33-x64 12 | - PYTHON: C:\Python34 13 | - PYTHON: C:\Python34-x64 14 | - PYTHON: C:\Python35 15 | - PYTHON: C:\Python35-x64 16 | - PYTHON: C:\Python36 17 | - PYTHON: C:\Python36-x64 18 | 19 | #install: 20 | # - "%PYTHON%\\python.exe -m pip install wheel" 21 | 22 | build: off 23 | 24 | test_script: 25 | - "%PYTHON%\\python.exe setup.py test" 26 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 100 3 | ignore = 4 | N802, # FIXME: tidy up camel case naming mess then re-enable these 5 | N803, 6 | 7 | W503, # Contradicts PEP8 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info/* 4 | dist/*.tar.gz 5 | /.mypy_cache 6 | /.coverage 7 | /htmlcov 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 2.7 4 | - 3.5 5 | - 3.6 6 | - 3.7 7 | - 3.8 8 | - pypy 9 | - pypy3 10 | 11 | install: 12 | - pip install codecov 13 | - pip install -r requirements-dev.txt 14 | - python setup.py develop 15 | 16 | script: 17 | - python -m pytest 18 | 19 | after_success: 20 | - codecov 21 | 22 | jobs: 23 | include: 24 | 25 | - name: "Formatting" 26 | python: 3.8 27 | install: 28 | - pip install black==19.10b0 29 | script: black --diff --check tvdb_api.py tests/*.py 30 | after_success: ignore 31 | 32 | - name: "Linting" 33 | python: 3.8 34 | install: 35 | - pip install -r requirements-dev.txt 36 | script: flake8 37 | after_success: ignore 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## `3.1` - 2021-04-29 4 | 5 | - Rename exceptions to conventional PEP8 naming syntax, e.g `tvdb_error` becomes `TvdbError`, `tvdb_episodenotfound` becomes `TvdbEpisodeNotFound` etc. All exceptions have changed. Backwards-compatible bindings to old names exist until next version (i.e will be removed in version 3.2) 6 | - Deprecate `Tvdb(forceConnect=...)` argument - had no effect in recent versions, and argument removed in next version. 7 | - New `TvdbDataNotFound` exception allows catching of all missing-data exceptions in on (`TvdbShowNotFound`, `TvdbSeasonNotFound`, `TvdbEpisodeNotFound`, `TvdbResourceNotFound` are now all subclasses of this) 8 | - Fix `ImportError: cannot import name '_to_bytes'` error due to change in [requests-cache 0.6.0](https://github.com/reclosedev/requests-cache/blob/master/HISTORY.md#060-2021-04-09) - [issue #92](https://github.com/dbr/tvdb_api/issues/92) 9 | - TVDB v1 API compatbility remapping has been removed: for example `t[show][1][23]['seriesname']` must now be `t[show][1][23]['seriesName']` 10 | 11 | ## `3.0.2` - 2020-05-16 12 | 13 | - Bug fix for `ConsoleUI` error `NameError: global name 'lid_map' is not defined` 14 | 15 | ## `3.0.1` - 2020-05-11 16 | 17 | - Reupload to PyPI to hopefully fix markdown rendering on PyPI page (may be related to [this bug](https://github.com/pypa/warehouse/issues/3664)) 18 | 19 | ## `3.0` - 2020-05-11 20 | 21 | - Important: Your own API key is now required to use this module. The default shared API key has been removed. 22 | Keys are easy to register via https://thetvdb.com/api-information 23 | - Include cache location info in debug logging 24 | - Drop support for Python 2.6 (EOL 2016), 3.3 (EOL 2013), 3.4 (EOL 2019) 25 | - Removed deprecated `Tvdb(debug=...)` argument - use logging module instead. 26 | E.g `logging.basicConfig(level=logging.DEBUG)` 27 | - Removed long deprecated `tvdb_ui` and `tvdb_exceptions` modules. 28 | Everything in these are accessible via the `tvdb_api` module 29 | - Correctly errors when failing to find show by ID - 30 | [issue #54](https://github.com/dbr/tvdb_api/issues/54) 31 | - Web-cache filename contains major version of Python to support 32 | side-by-side usage of `tvdb_api` in Python 2 and 3 33 | - Fix bug causing occasional `KeyError` when looking up lots of shows. 34 | [PR #65](https://github.com/dbr/tvdb_api/pull/65) 35 | 36 | 37 | ## `2.0` - 2017-09-16 38 | 39 | - Switch to TheTVDB new JSON based API - 40 | [issue #57](https://github.com/dbr/tvdb_api/issues/57) 41 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include UNLICENSE 2 | include README.md 3 | include tests/*.py 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `tvdb_api` 2 | [![PyPI][pypi-img]][pypi-link] [![Build Status][travis-img]][travis-link] [![codecov][coverage-img]][coverage-link] 3 | 4 | `tvdb_api` is an easy to use interface to [thetvdb.com][tvdb] 5 | 6 | It supports Python 2.7, and 3.5 onwards 7 | 8 | `tvnamer` has moved to a separate repository: [github.com/dbr/tvnamer][tvnamer] - it is a utility which uses `tvdb_api` to rename files from `some.show.s01e03.blah.abc.avi` to `Some Show - [01x03] - The Episode Name.avi` (which works by getting the episode name from `tvdb_api`) 9 | 10 | 11 | [tvdb]: http://thetvdb.com 12 | [tvnamer]: http://github.com/dbr/tvnamer 13 | [travis-link]: https://travis-ci.com/dbr/tvdb_api 14 | [travis-img]: https://travis-ci.com/dbr/tvdb_api.svg?branch=master 15 | [pypi-link]: https://pypi.org/project/tvdb-api/ 16 | [pypi-img]: https://img.shields.io/pypi/v/tvdb_api 17 | [coverage-link]: https://codecov.io/gh/dbr/tvdb_api 18 | [coverage-img]: https://codecov.io/gh/dbr/tvdb_api/branch/master/graph/badge.svg 19 | 20 | 21 | ## To install 22 | 23 | You can easily install `tvdb_api` via `pip` 24 | 25 | pip install --upgrade tvdb_api 26 | 27 | You may need to use sudo, depending on your setup: 28 | 29 | sudo pip install --upgrade tvdb_api 30 | 31 | ## Basic usage 32 | 33 | First initialise an instance of the `Tvdb` class with your API key: 34 | 35 | import tvdb_api 36 | t = tvdb_api.Tvdb() 37 | 38 | Note you must specify the apikey argument here, for example: 39 | 40 | t = Tvdb(apikey="ENTER YOUR API KEY HERE") # doctest:+SKIP 41 | 42 | See https://thetvdb.com/api-information to register a key. 43 | 44 | Then to use the API: 45 | 46 | episode = t['My Name Is Earl'][1][3] # get season 1, episode 3 of show 47 | print episode['episodename'] # Print episode name 48 | 49 | ## Registering an API key 50 | 51 | You must have an API key from in order to use this module. 52 | 53 | Registering for a key is easy to do and can be done within a few minutes - see the following page for details: 54 | 55 | 56 | 57 | Note: In `tvdb_api` v2 a default key was included for convenience. However over time this key became very heavily used and this causes problems for TheTVDB.com admins. This old shared key will be deprecated and removed at some point soon. 58 | 59 | ## Advanced usage 60 | 61 | Most of the documentation is in docstrings. The examples are tested (using doctest) so will always be up to date and working. 62 | 63 | The docstring for `Tvdb.__init__` lists all initialisation arguments, including support for non-English searches, custom "Select Series" interfaces and enabling the retrieval of banners and extended actor information. You can also override the default API key using `apikey`, recommended if you're using `tvdb_api` in a larger script or application 64 | 65 | ### Exceptions 66 | 67 | There are several exceptions you may catch, these can be imported from `tvdb_api`: 68 | 69 | - `tvdb_error` - this is raised when there is an error communicating with [thetvdb.com][tvdb] (a network error most commonly) 70 | - `tvdb_userabort` - raised when a user aborts the Select Series dialog (by `ctrl+c`, or entering `q`) 71 | - `tvdb_shownotfound` - raised when `t['show name']` cannot find anything 72 | - `tvdb_seasonnotfound` - raised when the requested series (`t['show name][99]`) does not exist 73 | - `tvdb_episodenotfound` - raised when the requested episode (`t['show name][1][99]`) does not exist. 74 | - `tvdb_attributenotfound` - raised when the requested attribute is not found (`t['show name']['an attribute']`, `t['show name'][1]['an attribute']`, or ``t['show name'][1][1]['an attribute']``) 75 | 76 | ### Series data 77 | 78 | All data exposed by [thetvdb.com][tvdb] is accessible via the `Show` class. A Show is retrieved by doing.. 79 | 80 | >>> import tvdb_api 81 | >>> t = tvdb_api.Tvdb() 82 | >>> show = t['scrubs'] 83 | >>> type(show) 84 | 85 | 86 | For example, to find out what network Scrubs is aired: 87 | 88 | >>> t['scrubs']['network'] 89 | u'ABC' 90 | 91 | The data is stored in an attribute named `data`, within the Show instance: 92 | 93 | >>> t['scrubs'].data.keys() 94 | ['networkid', 'rating', 'airs_dayofweek', 'contentrating', 'seriesname', 'id', 'airs_time', 'network', 'fanart', 'lastupdated', 'actors', 'ratingcount', 'status', 'added', 'poster', 'tms_wanted_old', 'imdb_id', 'genre', 'banner', 'seriesid', 'language', 'zap2it_id', 'addedby', 'firstaired', 'runtime', 'overview'] 95 | 96 | Although each element is also accessible via `t['scrubs']` for ease-of-use: 97 | 98 | >>> t['scrubs']['rating'] 99 | u'9.0' 100 | 101 | This is the recommended way of retrieving "one-off" data (for example, if you are only interested in "seriesname"). If you wish to iterate over all data, or check if a particular show has a specific piece of data, use the `data` attribute, 102 | 103 | >>> 'rating' in t['scrubs'].data 104 | True 105 | 106 | ### Banners and actors 107 | 108 | Since banners and actors are separate XML files, retrieving them by default is undesirable. If you wish to retrieve banners (and other fanart), use the `banners` Tvdb initialisation argument: 109 | 110 | >>> from tvdb_api import Tvdb 111 | >>> t = Tvdb(banners = True) 112 | 113 | Then access the data using a `Show`'s `_banner` key: 114 | 115 | >>> t['scrubs']['_banners'].keys() 116 | ['fanart', 'poster', 'series', 'season'] 117 | 118 | The banner data structure will be improved in future versions. 119 | 120 | Extended actor data is accessible similarly: 121 | 122 | >>> t = Tvdb(actors = True) 123 | >>> actors = t['scrubs']['_actors'] 124 | >>> actors[0] 125 | 126 | >>> actors[0].keys() 127 | ['sortorder', 'image', 'role', 'id', 'name'] 128 | >>> actors[0]['role'] 129 | u'Dr. John Michael "J.D." Dorian' 130 | 131 | Remember a simple list of actors is accessible via the default Show data: 132 | 133 | >>> t['scrubs']['actors'] 134 | u'|Zach Braff|Donald Faison|Sarah Chalke|Judy Reyes|John C. McGinley|Neil Flynn|Ken Jenkins|Christa Miller|Aloma Wright|Robert Maschio|Sam Lloyd|Travis Schuldt|Johnny Kastl|Heather Graham|Michael Mosley|Kerry Bish\xe9|Dave Franco|Eliza Coupe|' 135 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # `tvdb_api` release procedure 2 | 3 | 1. Ensure CHANGELOG is up to date 4 | 2. Ensure tests are passing (CI and run again locally) 5 | 3. Verify settings in `setup.py` (e.g supported Python versions) 6 | 4. Bump version in setup.py and `tvdb_api.py` 7 | 5. Bump version/release date in CHANGELOG 8 | 6. Push changes to git 9 | 7. `python setup.py sdist upload` 10 | 8. Tag change, `git tag -a 0.0etc` 11 | 9. Push tag, `git push --tags` 12 | 10. Verify https://pypi.org/project/tvdb_api/ 13 | 11. Verify via virtual env 14 | 15 | mkvirtualenv tvdbtest 16 | pip install tvdb_api 17 | python -c 'import tvdb_api; t = tvdb_api.Tvdb(); print t["scrubs"][1][2]' 18 | deactivate 19 | rmvirtualenv tvdbtest 20 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2012 Ben Dickson (dbr) 2 | 3 | This is free and unencumbered software released into the public domain. 4 | 5 | Anyone is free to copy, modify, publish, use, compile, sell, or 6 | distribute this software, either in source code form or as a compiled 7 | binary, for any purpose, commercial or non-commercial, and by any 8 | means. 9 | 10 | In jurisdictions that recognize copyright laws, the author or authors 11 | of this software dedicate any and all copyright interest in the 12 | software to the public domain. We make this dedication for the benefit 13 | of the public at large and to the detriment of our heirs and 14 | successors. We intend this dedication to be an overt act of 15 | relinquishment in perpetuity of all present and future rights to this 16 | software under copyright law. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | For more information, please refer to 27 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 100 3 | skip-string-normalization = true 4 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --cov=tvdb_api 3 | 4 | env = 5 | TVDB_API_KEY=d48665c58c1a3c3bcd0c78da82df4fab 6 | # API key for tvdb_api test use only. New keys can easily be registered at https://thetvdb.com/api-information 7 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | pytest==5.4; python_version > '3.0' 2 | pytest==4.6; python_version == '2.7' 3 | coverage 4 | pytest-cov==2.8 5 | pytest-env==0.6 6 | flake8==3.8 7 | pep8-naming==0.10 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from setuptools import setup 3 | 4 | # Load README 5 | from os import path 6 | this_directory = path.abspath(path.dirname(__file__)) 7 | if sys.version_info[0] == 2: 8 | with open(path.join(this_directory, 'README.md')) as f: 9 | long_description = f.read().decode("utf-8") 10 | else: 11 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: 12 | long_description = f.read() 13 | 14 | setup( 15 | name='tvdb_api', 16 | version='3.1.0', 17 | 18 | author='dbr/Ben', 19 | description='Interface to thetvdb.com', 20 | url='http://github.com/dbr/tvdb_api', 21 | 22 | long_description=long_description, 23 | long_description_content_type='text/markdown', 24 | 25 | py_modules=['tvdb_api'], 26 | install_requires=['requests_cache', 'requests'], 27 | 28 | classifiers=[ 29 | "Intended Audience :: Developers", 30 | "Natural Language :: English", 31 | "Operating System :: OS Independent", 32 | "Programming Language :: Python", 33 | "Programming Language :: Python :: 2", 34 | "Programming Language :: Python :: 2.7", 35 | "Programming Language :: Python :: 3.5", 36 | "Programming Language :: Python :: 3.6", 37 | "Programming Language :: Python :: 3.7", 38 | "Programming Language :: Python :: 3.8", 39 | "Topic :: Multimedia", 40 | "Topic :: Utilities", 41 | "Topic :: Software Development :: Libraries :: Python Modules", 42 | "License :: Public Domain", 43 | ] 44 | ) 45 | -------------------------------------------------------------------------------- /tests/httpcache/07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854 -------------------------------------------------------------------------------- /tests/httpcache/08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264 -------------------------------------------------------------------------------- /tests/httpcache/0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892 -------------------------------------------------------------------------------- /tests/httpcache/120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6 -------------------------------------------------------------------------------- /tests/httpcache/19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1 -------------------------------------------------------------------------------- /tests/httpcache/1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f -------------------------------------------------------------------------------- /tests/httpcache/234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b -------------------------------------------------------------------------------- /tests/httpcache/26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00 -------------------------------------------------------------------------------- /tests/httpcache/28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a -------------------------------------------------------------------------------- /tests/httpcache/2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7 -------------------------------------------------------------------------------- /tests/httpcache/33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd -------------------------------------------------------------------------------- /tests/httpcache/376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52 -------------------------------------------------------------------------------- /tests/httpcache/3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4 -------------------------------------------------------------------------------- /tests/httpcache/3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172 -------------------------------------------------------------------------------- /tests/httpcache/3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f -------------------------------------------------------------------------------- /tests/httpcache/409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6 -------------------------------------------------------------------------------- /tests/httpcache/440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f -------------------------------------------------------------------------------- /tests/httpcache/44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054 -------------------------------------------------------------------------------- /tests/httpcache/45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91 -------------------------------------------------------------------------------- /tests/httpcache/4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36 -------------------------------------------------------------------------------- /tests/httpcache/4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194 -------------------------------------------------------------------------------- /tests/httpcache/4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524 -------------------------------------------------------------------------------- /tests/httpcache/4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19 -------------------------------------------------------------------------------- /tests/httpcache/4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0 -------------------------------------------------------------------------------- /tests/httpcache/4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3 -------------------------------------------------------------------------------- /tests/httpcache/52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0 -------------------------------------------------------------------------------- /tests/httpcache/5a6d8f221f3c375f3b0fd8e89773a859fb4301dab5f53bc9d34d8e33bbc431dc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/5a6d8f221f3c375f3b0fd8e89773a859fb4301dab5f53bc9d34d8e33bbc431dc -------------------------------------------------------------------------------- /tests/httpcache/5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26 -------------------------------------------------------------------------------- /tests/httpcache/6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72 -------------------------------------------------------------------------------- /tests/httpcache/6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885 -------------------------------------------------------------------------------- /tests/httpcache/6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8 -------------------------------------------------------------------------------- /tests/httpcache/7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742 -------------------------------------------------------------------------------- /tests/httpcache/7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60 -------------------------------------------------------------------------------- /tests/httpcache/85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55 -------------------------------------------------------------------------------- /tests/httpcache/89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf -------------------------------------------------------------------------------- /tests/httpcache/91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7 -------------------------------------------------------------------------------- /tests/httpcache/923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c -------------------------------------------------------------------------------- /tests/httpcache/954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b -------------------------------------------------------------------------------- /tests/httpcache/9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9 -------------------------------------------------------------------------------- /tests/httpcache/9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216 -------------------------------------------------------------------------------- /tests/httpcache/9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766 -------------------------------------------------------------------------------- /tests/httpcache/9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03 -------------------------------------------------------------------------------- /tests/httpcache/a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511 -------------------------------------------------------------------------------- /tests/httpcache/a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd -------------------------------------------------------------------------------- /tests/httpcache/b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d -------------------------------------------------------------------------------- /tests/httpcache/bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745 -------------------------------------------------------------------------------- /tests/httpcache/c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b -------------------------------------------------------------------------------- /tests/httpcache/c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4 -------------------------------------------------------------------------------- /tests/httpcache/cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088 -------------------------------------------------------------------------------- /tests/httpcache/cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7 -------------------------------------------------------------------------------- /tests/httpcache/ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3 -------------------------------------------------------------------------------- /tests/httpcache/cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735 -------------------------------------------------------------------------------- /tests/httpcache/d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a -------------------------------------------------------------------------------- /tests/httpcache/d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96 -------------------------------------------------------------------------------- /tests/httpcache/d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd -------------------------------------------------------------------------------- /tests/httpcache/e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948 -------------------------------------------------------------------------------- /tests/httpcache/e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea -------------------------------------------------------------------------------- /tests/httpcache/e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373 -------------------------------------------------------------------------------- /tests/httpcache/e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714 -------------------------------------------------------------------------------- /tests/httpcache/e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4 -------------------------------------------------------------------------------- /tests/httpcache/e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791 -------------------------------------------------------------------------------- /tests/httpcache/ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e -------------------------------------------------------------------------------- /tests/httpcache/f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51 -------------------------------------------------------------------------------- /tests/httpcache/f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c -------------------------------------------------------------------------------- /tests/httpcache/f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761 -------------------------------------------------------------------------------- /tests/httpcache/f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c -------------------------------------------------------------------------------- /tests/httpcache/f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d -------------------------------------------------------------------------------- /tests/httpcache/f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache/f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5 -------------------------------------------------------------------------------- /tests/httpcache_py2/07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/07af40cf1941f2ad4d3bcc92cbc864be776f0398dac9e504692f8a499ff69854 -------------------------------------------------------------------------------- /tests/httpcache_py2/08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/08b448975b0a5635d4c85e5b358c18d9e523e809e7a7b998789a138f9f10f264 -------------------------------------------------------------------------------- /tests/httpcache_py2/0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/0997572089f4e42247f2bb6b5de22c20f4efbd50ec4bb1a4c4e336057cd16892 -------------------------------------------------------------------------------- /tests/httpcache_py2/120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/120fc248dc0691db22506afd64bbf99d06ebf9be088f63347c330921808e3bf6 -------------------------------------------------------------------------------- /tests/httpcache_py2/19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/19b1ca273ef7294dc13469f41e29683e8a4aabe96913c7269a711bafb31f72f1 -------------------------------------------------------------------------------- /tests/httpcache_py2/1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/1a8316738ed28a9bbe32d269d9f6366a9633aa0516042b51eef62462f49aaf5f -------------------------------------------------------------------------------- /tests/httpcache_py2/234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/234bddbc9ea09e34c62c96557791c9bea194555b9670b46316d326a2dcb0a11b -------------------------------------------------------------------------------- /tests/httpcache_py2/26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/26443651ad88ed46defce0f3a7f3a17ca4d5eeca0301786ec6313a8a8c3b2e00 -------------------------------------------------------------------------------- /tests/httpcache_py2/28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/28b5e71822e2d336b82aa7ef932656e60eb465199160c6a87d26e37e3126bd2a -------------------------------------------------------------------------------- /tests/httpcache_py2/2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/2c3d26638e042fcc68940b914a8506682a7c798c8e86414438dde46202130ba7 -------------------------------------------------------------------------------- /tests/httpcache_py2/33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/33cd05d6ba0271f5fe6929d2e3663d0e6a055e07290cc7508e674dbfce6ed1dd -------------------------------------------------------------------------------- /tests/httpcache_py2/376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/376f777caac26b557bfc81adf35b0e42d9df70fc98aae5bdbcba0b525cac5c52 -------------------------------------------------------------------------------- /tests/httpcache_py2/3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/3afb51c5a10cdc00db1f61a2560dcf8c688eaa84a843cf504aff22d7952378a4 -------------------------------------------------------------------------------- /tests/httpcache_py2/3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/3b184ea30db8d17f065568dbb57e564212f5959916fe4d5cf172824de1553172 -------------------------------------------------------------------------------- /tests/httpcache_py2/3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/3dda1f269caf9c7ccfe5e0c7231101498cb2e7906421406dda361b91a644673f -------------------------------------------------------------------------------- /tests/httpcache_py2/409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/409edd232e2c12ee61953fe3161938a21046926e27e5787065e1c24fc74817d6 -------------------------------------------------------------------------------- /tests/httpcache_py2/440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/440167f3f49637d2c611f0d642d1f7fa7c3402580fdfabb72d5f4c4008ba7f2f -------------------------------------------------------------------------------- /tests/httpcache_py2/44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/44e3b9348797967b2787b76b2b42c6455eaf5d0e6b8ceb3b19eee37def532054 -------------------------------------------------------------------------------- /tests/httpcache_py2/45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/45d6090db55365c3bdd68687567524b93169620435d719453dc2f61fb3105f91 -------------------------------------------------------------------------------- /tests/httpcache_py2/4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4780a4e991ff622b9bd5ae95b8c298028b4a36ce43c6d4878186cf7c24158a36 -------------------------------------------------------------------------------- /tests/httpcache_py2/4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4c269d041e56b18baf5bb8e41fff9748d2bbf4683e58e7aadb186cef2a15c194 -------------------------------------------------------------------------------- /tests/httpcache_py2/4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4d001018f1a474826c8c29b96608689bba4b72e8ff6a3584bcf30cba5e42b524 -------------------------------------------------------------------------------- /tests/httpcache_py2/4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4d2c98cc0c7eadc98a0bb5745c1dd501164714ca896eccc89f57b77f9ec24e19 -------------------------------------------------------------------------------- /tests/httpcache_py2/4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4f43f35247445e44cc2cd623b595da442ce9696a0cd6e40e1e857337935078a0 -------------------------------------------------------------------------------- /tests/httpcache_py2/4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/4fed5d626a82be9f4a17e8a8c59b02714ebefa2819394d82350002f609185ac3 -------------------------------------------------------------------------------- /tests/httpcache_py2/52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/52910765baba4f1dc0cc0091110b65cb88218095b64426cbdbce92d60362b7d0 -------------------------------------------------------------------------------- /tests/httpcache_py2/5a6d8f221f3c375f3b0fd8e89773a859fb4301dab5f53bc9d34d8e33bbc431dc: -------------------------------------------------------------------------------- 1 | (ccopy_reg 2 | _reconstructor 3 | p1 4 | (crequests_cache.backends.base 5 | _Store 6 | p2 7 | c__builtin__ 8 | object 9 | p3 10 | NtRp4 11 | (dp5 12 | S'cookies' 13 | p6 14 | g1 15 | (crequests.cookies 16 | RequestsCookieJar 17 | p7 18 | g3 19 | NtRp8 20 | (dp9 21 | S'_now' 22 | p10 23 | I1593949737 24 | sS'_policy' 25 | p11 26 | (icookielib 27 | DefaultCookiePolicy 28 | p12 29 | (dp13 30 | S'strict_rfc2965_unverifiable' 31 | p14 32 | I01 33 | sS'strict_ns_domain' 34 | p15 35 | I0 36 | sS'_allowed_domains' 37 | p16 38 | NsS'rfc2109_as_netscape' 39 | p17 40 | NsS'rfc2965' 41 | p18 42 | I00 43 | sS'strict_domain' 44 | p19 45 | I00 46 | sS'_now' 47 | p20 48 | I1593949737 49 | sS'strict_ns_set_path' 50 | p21 51 | I00 52 | sS'strict_ns_unverifiable' 53 | p22 54 | I00 55 | sS'strict_ns_set_initial_dollar' 56 | p23 57 | I00 58 | sS'hide_cookie2' 59 | p24 60 | I00 61 | sS'_blocked_domains' 62 | p25 63 | (tsS'netscape' 64 | p26 65 | I01 66 | sbsS'_cookies' 67 | p27 68 | (dp28 69 | sbsS'_content' 70 | p29 71 | S'{"Error":"ID: 999999999999999999999999 not found"}' 72 | p30 73 | sS'encoding' 74 | p31 75 | S'utf-8' 76 | p32 77 | sS'url' 78 | p33 79 | Vhttps://api.thetvdb.com/series/999999999999999999999999 80 | p34 81 | sS'status_code' 82 | p35 83 | I404 84 | sS'request' 85 | p36 86 | g1 87 | (crequests.models 88 | PreparedRequest 89 | p37 90 | g3 91 | NtRp38 92 | (dp39 93 | S'body' 94 | p40 95 | Nsg33 96 | S'https://api.thetvdb.com/series/999999999999999999999999' 97 | p41 98 | sS'hooks' 99 | p42 100 | (lp43 101 | sS'headers' 102 | p44 103 | g1 104 | (crequests.structures 105 | CaseInsensitiveDict 106 | p45 107 | g3 108 | NtRp46 109 | (dp47 110 | S'_store' 111 | p48 112 | ccollections 113 | OrderedDict 114 | p49 115 | ((lp50 116 | (lp51 117 | S'connection' 118 | p52 119 | a(S'Connection' 120 | S'keep-alive' 121 | tp53 122 | aa(lp54 123 | S'accept-encoding' 124 | p55 125 | a(S'Accept-Encoding' 126 | S'gzip, deflate' 127 | tp56 128 | aa(lp57 129 | S'accept' 130 | p58 131 | a(S'Accept' 132 | S'application/json' 133 | p59 134 | tp60 135 | aa(lp61 136 | S'user-agent' 137 | p62 138 | a(S'User-Agent' 139 | S'python-requests/2.24.0' 140 | tp63 141 | aa(lp64 142 | S'accept-language' 143 | p65 144 | a(S'Accept-Language' 145 | S'en' 146 | tp66 147 | aa(lp67 148 | S'content-type' 149 | p68 150 | a(S'Content-Type' 151 | g59 152 | tp69 153 | aa(lp70 154 | S'authorization' 155 | p71 156 | a(S'Authorization' 157 | VBearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTQ1NTQ1MzYsImlkIjoidHZkYl9hcGkgdGVzdHMiLCJvcmlnX2lhdCI6MTU5Mzk0OTczNn0.DuXR2ZLMlAJDkGt_AQNWg6Qc3A_5Dsl7Y4Lqwgb5Sgdn2jUW1Mh5KQdpAMLhYGkbTWOwPsU_e2HSXzrC0SaXZb7KBbvMLa3xpgzdjirXrnF9yY1lnQCI8zhwKC7XF-WvtfvaTVDV9cVp6IpK_DHAmYNosjJBwM5Fi3D9UePBoeNgtaxgiDhKcyOvpRYrzkLS3t0re_J288hRwBUaUhCVZQ-FnUV8ST_4fZbowOVAaaXYbZmNnkMgw9eHRW_mtMekH-jTHrP_a9mVUUOuOj-mE6_QVBbEsddZvshe4RGHoWlGk4aBxkJQuITNyNvw3gTR8EPvlo3b4NGf1BORUWgpXQ 158 | tp72 159 | aatRp73 160 | sbsS'_body_position' 161 | p74 162 | NsS'_cookies' 163 | p75 164 | g1 165 | (g7 166 | g3 167 | NtRp76 168 | (dp77 169 | g10 170 | I1593949737 171 | sg11 172 | (icookielib 173 | DefaultCookiePolicy 174 | p78 175 | (dp79 176 | g14 177 | I01 178 | sg15 179 | I0 180 | sg16 181 | Nsg17 182 | Nsg18 183 | I00 184 | sg19 185 | I00 186 | sg20 187 | I1593949737 188 | sg21 189 | I00 190 | sg22 191 | I00 192 | sg23 193 | I00 194 | sg24 195 | I00 196 | sg25 197 | (tsg26 198 | I01 199 | sbsg27 200 | (dp80 201 | sbsS'method' 202 | p81 203 | S'GET' 204 | p82 205 | sbsg44 206 | g1 207 | (g45 208 | g3 209 | NtRp83 210 | (dp84 211 | g48 212 | g49 213 | ((lp85 214 | (lp86 215 | S'content-type' 216 | p87 217 | a(S'Content-Type' 218 | p88 219 | S'application/json; charset=utf-8' 220 | p89 221 | tp90 222 | aa(lp91 223 | S'content-length' 224 | p92 225 | a(S'Content-Length' 226 | p93 227 | S'66' 228 | p94 229 | tp95 230 | aa(lp96 231 | S'connection' 232 | p97 233 | a(S'Connection' 234 | p98 235 | S'keep-alive' 236 | p99 237 | tp100 238 | aa(lp101 239 | S'date' 240 | p102 241 | a(S'Date' 242 | p103 243 | S'Sun, 05 Jul 2020 11:48:57 GMT' 244 | p104 245 | tp105 246 | aa(lp106 247 | S'cache-control' 248 | p107 249 | a(S'Cache-Control' 250 | p108 251 | S'private, max-age=86400' 252 | p109 253 | tp110 254 | aa(lp111 255 | S'x-powered-by' 256 | p112 257 | a(S'X-Powered-By' 258 | p113 259 | S'Thundar!' 260 | p114 261 | tp115 262 | aa(lp116 263 | S'x-thetvdb-api-version' 264 | p117 265 | a(S'X-Thetvdb-Api-Version' 266 | p118 267 | S'3.0.0' 268 | p119 269 | tp120 270 | aa(lp121 271 | S'vary' 272 | p122 273 | a(S'Vary' 274 | p123 275 | S'Accept-Language' 276 | p124 277 | tp125 278 | aa(lp126 279 | S'x-cache' 280 | p127 281 | a(S'X-Cache' 282 | p128 283 | S'Error from cloudfront' 284 | p129 285 | tp130 286 | aa(lp131 287 | S'via' 288 | p132 289 | a(S'Via' 290 | p133 291 | S'1.1 53c50678e40ac01e17221f5619420630.cloudfront.net (CloudFront)' 292 | p134 293 | tp135 294 | aa(lp136 295 | S'x-amz-cf-pop' 296 | p137 297 | a(S'X-Amz-Cf-Pop' 298 | p138 299 | S'PER50-C1' 300 | p139 301 | tp140 302 | aa(lp141 303 | S'x-amz-cf-id' 304 | p142 305 | a(S'X-Amz-Cf-Id' 306 | p143 307 | S'fy5rlST7FqXcVpRw1TfrMvoXnEZtH0J6Tsdocl7fu2JL2_XDKGCT-g==' 308 | p144 309 | tp145 310 | aatRp146 311 | sbsS'raw' 312 | p147 313 | g1 314 | (crequests_cache.backends.base 315 | _RawStore 316 | p148 317 | g3 318 | NtRp149 319 | (dp150 320 | S'status' 321 | p151 322 | I404 323 | sS'strict' 324 | p152 325 | I01 326 | sg44 327 | g1 328 | (curllib3._collections 329 | HTTPHeaderDict 330 | p153 331 | g3 332 | NtRp154 333 | (dp155 334 | S'_container' 335 | p156 336 | g49 337 | ((lp157 338 | (lp158 339 | S'content-type' 340 | p159 341 | a(lp160 342 | g88 343 | ag89 344 | aaa(lp161 345 | S'content-length' 346 | p162 347 | a(lp163 348 | g93 349 | ag94 350 | aaa(lp164 351 | S'connection' 352 | p165 353 | a(lp166 354 | g98 355 | ag99 356 | aaa(lp167 357 | S'date' 358 | p168 359 | a(lp169 360 | g103 361 | ag104 362 | aaa(lp170 363 | S'cache-control' 364 | p171 365 | a(lp172 366 | g108 367 | ag109 368 | aaa(lp173 369 | S'x-powered-by' 370 | p174 371 | a(lp175 372 | g113 373 | ag114 374 | aaa(lp176 375 | S'x-thetvdb-api-version' 376 | p177 377 | a(lp178 378 | g118 379 | ag119 380 | aaa(lp179 381 | S'vary' 382 | p180 383 | a(lp181 384 | g123 385 | ag124 386 | aaa(lp182 387 | S'x-cache' 388 | p183 389 | a(lp184 390 | g128 391 | ag129 392 | aaa(lp185 393 | S'via' 394 | p186 395 | a(lp187 396 | g133 397 | ag134 398 | aaa(lp188 399 | S'x-amz-cf-pop' 400 | p189 401 | a(lp190 402 | g138 403 | ag139 404 | aaa(lp191 405 | S'x-amz-cf-id' 406 | p192 407 | a(lp193 408 | g143 409 | ag144 410 | aaatRp194 411 | sbsS'reason' 412 | p195 413 | S'Not Found' 414 | p196 415 | sS'version' 416 | p197 417 | I11 418 | sS'_original_response' 419 | p198 420 | (ihttplib 421 | HTTPResponse 422 | p199 423 | (dp200 424 | S'fp' 425 | p201 426 | Nsg151 427 | I404 428 | sS'will_close' 429 | p202 430 | I00 431 | sS'chunk_left' 432 | p203 433 | S'UNKNOWN' 434 | p204 435 | sS'length' 436 | p205 437 | I0 438 | sg152 439 | I01 440 | sg195 441 | g196 442 | sg197 443 | I11 444 | sS'debuglevel' 445 | p206 446 | I0 447 | sS'msg' 448 | p207 449 | (ihttplib 450 | HTTPMessage 451 | p208 452 | (dp209 453 | g201 454 | Nsg151 455 | S'' 456 | sS'startofbody' 457 | p210 458 | NsS'startofheaders' 459 | p211 460 | NsS'subtype' 461 | p212 462 | S'json' 463 | p213 464 | sS'type' 465 | p214 466 | S'application/json' 467 | p215 468 | sS'maintype' 469 | p216 470 | S'application' 471 | p217 472 | sg44 473 | (lp218 474 | S'Content-Type: application/json; charset=utf-8\r\n' 475 | p219 476 | aS'Content-Length: 66\r\n' 477 | p220 478 | aS'Connection: keep-alive\r\n' 479 | p221 480 | aS'Date: Sun, 05 Jul 2020 11:48:57 GMT\r\n' 481 | p222 482 | aS'Cache-Control: private, max-age=86400\r\n' 483 | p223 484 | aS'X-Powered-By: Thundar!\r\n' 485 | p224 486 | aS'X-Thetvdb-Api-Version: 3.0.0\r\n' 487 | p225 488 | aS'Vary: Accept-Language\r\n' 489 | p226 490 | aS'X-Cache: Error from cloudfront\r\n' 491 | p227 492 | aS'Via: 1.1 53c50678e40ac01e17221f5619420630.cloudfront.net (CloudFront)\r\n' 493 | p228 494 | aS'X-Amz-Cf-Pop: PER50-C1\r\n' 495 | p229 496 | aS'X-Amz-Cf-Id: fy5rlST7FqXcVpRw1TfrMvoXnEZtH0J6Tsdocl7fu2JL2_XDKGCT-g==\r\n' 497 | p230 498 | asS'dict' 499 | p231 500 | (dp232 501 | S'x-amz-cf-pop' 502 | p233 503 | S'PER50-C1' 504 | p234 505 | sS'content-length' 506 | p235 507 | S'66' 508 | p236 509 | sS'via' 510 | p237 511 | S'1.1 53c50678e40ac01e17221f5619420630.cloudfront.net (CloudFront)' 512 | p238 513 | sS'x-cache' 514 | p239 515 | S'Error from cloudfront' 516 | p240 517 | sS'x-powered-by' 518 | p241 519 | S'Thundar!' 520 | p242 521 | sS'vary' 522 | p243 523 | S'Accept-Language' 524 | p244 525 | sS'x-thetvdb-api-version' 526 | p245 527 | S'3.0.0' 528 | p246 529 | sS'connection' 530 | p247 531 | S'keep-alive' 532 | p248 533 | sS'x-amz-cf-id' 534 | p249 535 | S'fy5rlST7FqXcVpRw1TfrMvoXnEZtH0J6Tsdocl7fu2JL2_XDKGCT-g==' 536 | p250 537 | sS'cache-control' 538 | p251 539 | S'private, max-age=86400' 540 | p252 541 | sS'date' 542 | p253 543 | S'Sun, 05 Jul 2020 11:48:57 GMT' 544 | p254 545 | sS'content-type' 546 | p255 547 | S'application/json; charset=utf-8' 548 | p256 549 | ssS'typeheader' 550 | p257 551 | g256 552 | sS'encodingheader' 553 | p258 554 | NsS'seekable' 555 | p259 556 | I0 557 | sS'unixfrom' 558 | p260 559 | S'' 560 | sS'plisttext' 561 | p261 562 | S'; charset=utf-8' 563 | p262 564 | sS'plist' 565 | p263 566 | (lp264 567 | S'charset=utf-8' 568 | p265 569 | asbsS'chunked' 570 | p266 571 | I0 572 | sS'_method' 573 | p267 574 | g82 575 | sbsS'decode_content' 576 | p268 577 | I00 578 | sbsg195 579 | g196 580 | sS'history' 581 | p269 582 | (tsbcdatetime 583 | datetime 584 | p270 585 | (S'\x07\xe4\x07\x05\x0b09\n\xb3P' 586 | tRp271 587 | tp272 588 | . -------------------------------------------------------------------------------- /tests/httpcache_py2/5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/5ba778581d38aa49351ab40941ba3ceddcd7f504c8b5475b72f5765bd4200a26 -------------------------------------------------------------------------------- /tests/httpcache_py2/6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/6a6f4ff6442c50b20bad2fd73d65c6268d32b38220568a447321dc5b18fc8b72 -------------------------------------------------------------------------------- /tests/httpcache_py2/6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/6bdf7786ddc74a1d8f6bdfa281d0bb35f6b9566395abcdcfd6dfd1fead20e885 -------------------------------------------------------------------------------- /tests/httpcache_py2/6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/6d4cf6ea06bdc7a7270bd1844ee0f173ebdf2ae3cff58783dc625d637ae94dc8 -------------------------------------------------------------------------------- /tests/httpcache_py2/7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/7db9ef6084de388ccd4c76d8667fc42847d6d858e2e017f8e6df0f310de39742 -------------------------------------------------------------------------------- /tests/httpcache_py2/7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/7e5ab06171c96080e8ce8560a58ad2e7a7a8fc95b3093e33220087b44bb06d60 -------------------------------------------------------------------------------- /tests/httpcache_py2/85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/85b65f515e9e123877607048ad6e2782ecae85dd8abad14a0d75e5a5fffd6a55 -------------------------------------------------------------------------------- /tests/httpcache_py2/89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/89650088cebaae362bd35d3cc72a95b0a3ff73c2a4430e310ae837617c5720cf -------------------------------------------------------------------------------- /tests/httpcache_py2/91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/91dd1fbdbeabb2ea39817fa18ccf165a59c365a3d98117c671b109986c38a9d7 -------------------------------------------------------------------------------- /tests/httpcache_py2/923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/923a0d0abc87170accbe9c71aa83d09585645f66cc9d27f5a1925adb0291115c -------------------------------------------------------------------------------- /tests/httpcache_py2/954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/954dbfd278fe22fdbb9e6048f89724601e465e2c69c528d6dba08b37424c959b -------------------------------------------------------------------------------- /tests/httpcache_py2/9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/9a5546aeedd514758fd504cfc646d4a9181cd4049e045ed299df296824a3c3d9 -------------------------------------------------------------------------------- /tests/httpcache_py2/9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/9c7acbc0aa92fd521af1fe3d72ba9d76ec2415c31f131a4313c1f330da994216 -------------------------------------------------------------------------------- /tests/httpcache_py2/9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/9cb08f4cb7b3c44219931c1d5250da2f633a1cc573bfa5a4531e509ace26c766 -------------------------------------------------------------------------------- /tests/httpcache_py2/9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/9efad0ef561e1f8445b553c6e6f8e8769654c6eb7b779198d0b3a126df269a03 -------------------------------------------------------------------------------- /tests/httpcache_py2/a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/a28ac291f4761e05cd1be958a31d365100761ce3d86300bd2a854a92a57c9511 -------------------------------------------------------------------------------- /tests/httpcache_py2/a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/a9a62262de0623d69a3145d8563f6dbc5d810aa821d32a78a8bb14c6eef7cedd -------------------------------------------------------------------------------- /tests/httpcache_py2/b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/b52d9259bbdc9edea35b3ca29d5bb4cf3bd33901fe3222449b005d6ad591173d -------------------------------------------------------------------------------- /tests/httpcache_py2/bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/bd8fa3a1b728c133437cc0c7e0ac2161667d326630775e547e05922ba8bde745 -------------------------------------------------------------------------------- /tests/httpcache_py2/c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/c25b8787e74c5f6d0ccc874ac79bd419cafb4e51f2ac6b5aee7e5ed906c8d65b -------------------------------------------------------------------------------- /tests/httpcache_py2/c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/c69825366290adb9a56814216798578d9fd8d3c0676ed430ce60c20e7ee3a7c4 -------------------------------------------------------------------------------- /tests/httpcache_py2/cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/cda2efd6e84d746454fcc08d558ccf0349e84e0ca6d206a84b0d722f805f8088 -------------------------------------------------------------------------------- /tests/httpcache_py2/cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/cdc28d5a38ad2cd008e01f315a0dde695057f9565271f5afacacc0efebc770d7 -------------------------------------------------------------------------------- /tests/httpcache_py2/ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/ce8430a86549723e0980592c018013f71415858d54ac50e01d9d8308f8fecff3 -------------------------------------------------------------------------------- /tests/httpcache_py2/cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/cfecf585195efd0811de3ec8d389c7d3280cb6bc2bdcc82aed476a63a943d735 -------------------------------------------------------------------------------- /tests/httpcache_py2/d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/d5bc81d09b5367e75bbf157ccc4edcfd75712f9add2ef61a3181b602be44a10a -------------------------------------------------------------------------------- /tests/httpcache_py2/d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/d701387e057c763069e41901de1a62a9457a34ed5511cc1771eec11c23fa9d96 -------------------------------------------------------------------------------- /tests/httpcache_py2/d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/d82967c274a0aa07e929f46b354df1d9cc3393d782980fc2f1fbfc9d47cfa7cd -------------------------------------------------------------------------------- /tests/httpcache_py2/e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e085517c970edb992793b75e7fb38fae8f8b7d27dfb3f3fdfe54e3505dc02948 -------------------------------------------------------------------------------- /tests/httpcache_py2/e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e57e4ad48cae5aebb17daf7e1627444d94ef18817b9ff9977c08eb73006afbea -------------------------------------------------------------------------------- /tests/httpcache_py2/e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e707a7b250a2b956afbd389bcef27656f02e864040742e6350b0a396ec8b7373 -------------------------------------------------------------------------------- /tests/httpcache_py2/e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e75741a2c491d5e7230487f235228bbef5c3078c2acddf140eb85c263d498714 -------------------------------------------------------------------------------- /tests/httpcache_py2/e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e77dda0ab8dab983730036979c189c494654d54f5dd69d139e62eff277348bd4 -------------------------------------------------------------------------------- /tests/httpcache_py2/e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/e94356f5c11edc5ec9a18cf6245b1fb7b6499e85da2b384fbba6bc491c84d791 -------------------------------------------------------------------------------- /tests/httpcache_py2/ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/ed66cf25e2fbba5595506d9f9eb10b52db7e469fd13b79752c0ce065678ee33e -------------------------------------------------------------------------------- /tests/httpcache_py2/f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f25022147290ac7decc62ea053da8d5ea5f4867edbb654cdf186f81c9b8dbc51 -------------------------------------------------------------------------------- /tests/httpcache_py2/f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f37fc6bb9f19241f31480f522e74aabcf49b31f0a4dfe796a79f53951591625c -------------------------------------------------------------------------------- /tests/httpcache_py2/f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f38fc6c26761954b3c12ea0d4f9a7c29472efe2b7c5347b4d701fa4c3a39b761 -------------------------------------------------------------------------------- /tests/httpcache_py2/f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f3e99227d7e57546da431572e6b92a491ee4fab646f58c7869e466006ab8ed0c -------------------------------------------------------------------------------- /tests/httpcache_py2/f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f53622b2ec8ff128a26fb13444fd43d5184929e99e9aee703c457e102102226d -------------------------------------------------------------------------------- /tests/httpcache_py2/f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbr/tvdb_api/ce0382181a9e08a5113bfee0fed2c78f8b1e613f/tests/httpcache_py2/f5b84280fe0914746d26e57e7592ea4f516be3f3995f01ee9d9d73b647e721c5 -------------------------------------------------------------------------------- /tests/test_tvdb_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding:utf-8 3 | 4 | # author:dbr/Ben 5 | # project:tvdb_api 6 | # repository:http://github.com/dbr/tvdb_api 7 | # license:unlicense (http://unlicense.org/) 8 | 9 | """Unittests for tvdb_api 10 | """ 11 | 12 | import os 13 | import sys 14 | import types 15 | import datetime 16 | import pytest 17 | 18 | # Force parent directory onto path 19 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 20 | 21 | import tvdb_api # noqa: E402 22 | from tvdb_api import ( # noqa: E402 23 | tvdb_shownotfound, 24 | tvdb_seasonnotfound, 25 | tvdb_episodenotfound, 26 | tvdb_attributenotfound, 27 | ) 28 | 29 | 30 | import requests_cache.backends # noqa: E402 31 | import requests_cache.backends.base # noqa: E402 32 | 33 | 34 | try: 35 | from collections.abc import MutableMapping 36 | except ImportError: 37 | from collections import MutableMapping 38 | 39 | import pickle # noqa: E402 40 | 41 | 42 | IS_PY2 = sys.version_info[0] == 2 43 | 44 | if IS_PY2: 45 | # Not really but good enough for backwards-compat here 46 | FileNotFoundError = IOError 47 | 48 | 49 | # By default tests use persistent (committed to Git) cache. 50 | # Setting this env-var allows the cache to be populated. 51 | # This is necessary if, say, adding new test case or TVDB response changes. 52 | # It is recommended to clear the cache directory before re-populating the cache. 53 | ALLOW_CACHE_WRITE_ENV_VAR = "TVDB_API_TESTS_ALLOW_CACHE_WRITE" 54 | ALLOW_CACHE_WRITE = os.getenv(ALLOW_CACHE_WRITE_ENV_VAR, "0") == "1" 55 | 56 | 57 | class FileCacheDict(MutableMapping): 58 | def __init__(self, base_dir): 59 | self._base_dir = base_dir 60 | 61 | def __getitem__(self, key): 62 | path = os.path.join(self._base_dir, key) 63 | try: 64 | with open(path, "rb") as f: 65 | data = pickle.load(f) 66 | return data 67 | except FileNotFoundError: 68 | if not ALLOW_CACHE_WRITE: 69 | raise RuntimeError("No cache file found %s" % path) 70 | raise KeyError 71 | 72 | def __setitem__(self, key, item): 73 | if ALLOW_CACHE_WRITE: 74 | path = os.path.join(self._base_dir, key) 75 | with open(path, "wb") as f: 76 | # Dump with protocol 2 to allow Python 2.7 support 77 | f.write(pickle.dumps(item, protocol=2)) 78 | else: 79 | raise RuntimeError( 80 | "Requested uncached URL and $%s not set to 1" % (ALLOW_CACHE_WRITE_ENV_VAR) 81 | ) 82 | 83 | def __delitem__(self, key): 84 | raise RuntimeError("Removing items from test-cache not supported") 85 | 86 | def __len__(self): 87 | raise NotImplementedError() 88 | 89 | def __iter__(self): 90 | raise NotImplementedError() 91 | 92 | def clear(self): 93 | raise NotImplementedError() 94 | 95 | def __str__(self): 96 | return str(dict(self.items())) 97 | 98 | 99 | class FileCache(requests_cache.backends.base.BaseCache): 100 | def __init__(self, _name, fc_base_dir, **options): 101 | super(FileCache, self).__init__(**options) 102 | self.responses = FileCacheDict(base_dir=fc_base_dir) 103 | self.keys_map = FileCacheDict(base_dir=fc_base_dir) 104 | 105 | 106 | requests_cache.backends.registry['tvdb_api_file_cache'] = FileCache 107 | 108 | 109 | def get_test_cache_session(): 110 | here = os.path.dirname(os.path.abspath(__file__)) 111 | additional = "_py2" if sys.version_info[0] == 2 else "" 112 | sess = requests_cache.CachedSession( 113 | backend="tvdb_api_file_cache", 114 | fc_base_dir=os.path.join(here, "httpcache%s" % additional), 115 | include_get_headers=True, 116 | allowable_codes=(200, 404), 117 | ) 118 | sess.cache.create_key = types.MethodType(tvdb_api.create_key, sess.cache) 119 | return sess 120 | 121 | 122 | class TestTvdbBasic: 123 | # Used to store the cached instance of Tvdb() 124 | t = None 125 | 126 | @classmethod 127 | def setup_class(cls): 128 | if cls.t is None: 129 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False) 130 | 131 | def test_different_case(self): 132 | """Checks the auto-correction of show names is working. 133 | It should correct the weirdly capitalised 'sCruBs' to 'Scrubs' 134 | """ 135 | assert self.t['scrubs'][1][4]['episodeName'] == 'My Old Lady' 136 | assert self.t['sCruBs']['seriesName'] == 'Scrubs' 137 | 138 | def test_spaces(self): 139 | """Checks shownames with spaces 140 | """ 141 | assert self.t['My Name Is Earl']['seriesName'] == 'My Name Is Earl' 142 | assert self.t['My Name Is Earl'][1][4]['episodeName'] == 'Faked My Own Death' 143 | 144 | def test_numeric(self): 145 | """Checks numeric show names 146 | """ 147 | assert self.t['24'][2][20]['episodeName'] == 'Day 2: 3:00 A.M. - 4:00 A.M.' 148 | assert self.t['24']['seriesName'] == '24' 149 | 150 | def test_show_iter(self): 151 | """Iterating over a show returns each seasons 152 | """ 153 | assert len([season for season in self.t['scrubs']]) == 10 154 | 155 | def test_season_iter(self): 156 | """Iterating over a show returns episodes 157 | """ 158 | assert len([episode for episode in self.t['scrubs'][1]]) == 24 159 | 160 | def test_get_episode_overview(self): 161 | """Checks episode overview is retrieved correctly. 162 | """ 163 | assert self.t['Scrubs'][1][6]['overview'].startswith( 164 | 'Dr. Cox is still facing the threat of suspension' 165 | ) 166 | 167 | try: 168 | self.t['Scrubs']['something nonsensical'] 169 | except tvdb_attributenotfound: 170 | pass # good 171 | else: 172 | raise AssertionError("Expected attribute error") 173 | 174 | def test_get_parent(self): 175 | """Check accessing series from episode instance 176 | """ 177 | show = self.t['Scrubs'] 178 | season = show[1] 179 | episode = show[1][1] 180 | 181 | assert season.show == show 182 | assert episode.season == season 183 | assert episode.season.show == show 184 | 185 | def test_no_season(self): 186 | show = self.t['Katekyo Hitman Reborn'] 187 | print(tvdb_api) 188 | print(show[1][1]) 189 | 190 | 191 | class TestTvdbErrors: 192 | t = None 193 | 194 | @classmethod 195 | def setup_class(cls): 196 | if cls.t is None: 197 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False) 198 | 199 | def test_seasonnotfound(self): 200 | """Checks exception is thrown when season doesn't exist. 201 | """ 202 | with pytest.raises(tvdb_seasonnotfound): 203 | self.t['Scrubs'][42] 204 | 205 | def test_shownotfound(self): 206 | """Checks exception is thrown when episode doesn't exist. 207 | """ 208 | with pytest.raises(tvdb_shownotfound): 209 | self.t['the fake show thingy'] 210 | 211 | def test_shownotfound_by_id(self): 212 | """Checks exception is thrown when episode doesn't exist. 213 | """ 214 | with pytest.raises(tvdb_shownotfound): 215 | self.t[999999999999999999999999] 216 | 217 | def test_episodenotfound(self): 218 | """Checks exception is raised for non-existent episode 219 | """ 220 | with pytest.raises(tvdb_episodenotfound): 221 | self.t['Scrubs'][1][30] 222 | 223 | def test_attributenamenotfound(self): 224 | """Checks exception is thrown for if an attribute isn't found. 225 | """ 226 | with pytest.raises(tvdb_attributenotfound): 227 | self.t['Scrubs'][1][6]['afakeattributething'] 228 | self.t['Scrubs']['afakeattributething'] 229 | 230 | 231 | class TestTvdbSearch: 232 | # Used to store the cached instance of Tvdb() 233 | t = None 234 | 235 | @classmethod 236 | def setup_class(cls): 237 | if cls.t is None: 238 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False) 239 | 240 | def test_search_len(self): 241 | """There should be only one result matching 242 | """ 243 | assert len(self.t['My Name Is Earl'].search('Faked My Own Death')) == 1 244 | 245 | def test_search_checkname(self): 246 | """Checks you can get the episode name of a search result 247 | """ 248 | assert self.t['Scrubs'].search('my first')[0]['episodeName'] == 'My First Day' 249 | assert ( 250 | self.t['My Name Is Earl'].search('Faked My Own Death')[0]['episodeName'] 251 | == 'Faked My Own Death' 252 | ) 253 | 254 | def test_search_multiresults(self): 255 | """Checks search can return multiple results 256 | """ 257 | assert len(self.t['Scrubs'].search('my first')) >= 3 258 | 259 | def test_search_no_params_error(self): 260 | """Checks not supplying search info raises TypeError""" 261 | with pytest.raises(TypeError): 262 | self.t['Scrubs'].search() 263 | 264 | def test_search_season(self): 265 | """Checks the searching of a single season""" 266 | assert len(self.t['Scrubs'][1].search("First")) == 3 267 | 268 | def test_search_show(self): 269 | """Checks the searching of an entire show""" 270 | assert len(self.t['CNNNN'].search('CNNNN', key='episodeName')) == 3 271 | 272 | def test_aired_on(self): 273 | """Tests aired_on show method""" 274 | sr = self.t['Scrubs'].aired_on(datetime.date(2001, 10, 2)) 275 | assert len(sr) == 1 276 | assert sr[0]['episodeName'] == u'My First Day' 277 | 278 | try: 279 | sr = self.t['Scrubs'].aired_on(datetime.date(1801, 1, 1)) 280 | except tvdb_episodenotfound: 281 | pass # Good 282 | else: 283 | raise AssertionError("expected episode not found exception") 284 | 285 | 286 | class TestTvdbData: 287 | # Used to store the cached instance of Tvdb() 288 | t = None 289 | 290 | @classmethod 291 | def setup_class(cls): 292 | if cls.t is None: 293 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False) 294 | 295 | def test_episode_data(self): 296 | """Check the firstaired value is retrieved 297 | """ 298 | assert self.t['lost']['firstAired'] == '2004-09-22' 299 | 300 | 301 | class TestTvdbMisc: 302 | # Used to store the cached instance of Tvdb() 303 | t = None 304 | 305 | @classmethod 306 | def setup_class(cls): 307 | if cls.t is None: 308 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=False) 309 | 310 | def test_repr_show(self): 311 | """Check repr() of Season 312 | """ 313 | assert ( 314 | repr(self.t['CNNNN']).replace("u'", "'") 315 | == "" 316 | ) 317 | 318 | def test_repr_season(self): 319 | """Check repr() of Season 320 | """ 321 | assert repr(self.t['CNNNN'][1]) == "" 322 | 323 | def test_repr_episode(self): 324 | """Check repr() of Episode 325 | """ 326 | assert repr(self.t['CNNNN'][1][1]).replace("u'", "'") == "" 327 | 328 | def test_available_langs(self): 329 | """Check available_languages returns something sane looking 330 | """ 331 | langs = self.t.available_languages() 332 | print(langs) 333 | assert "en" in langs 334 | 335 | 336 | class TestTvdbLanguages: 337 | def test_episode_name_french(self): 338 | """Check episode data is in French (language="fr") 339 | """ 340 | t = tvdb_api.Tvdb(cache=get_test_cache_session(), language="fr") 341 | assert t['scrubs'][1][1]['episodeName'] == "Mon premier jour" 342 | assert t['scrubs']['overview'].startswith(u"J.D. est un jeune m\xe9decin qui d\xe9bute") 343 | 344 | def test_episode_name_spanish(self): 345 | """Check episode data is in Spanish (language="es") 346 | """ 347 | t = tvdb_api.Tvdb(cache=get_test_cache_session(), language="es") 348 | assert t['scrubs'][1][1]['episodeName'] == u'Mi primer día' 349 | assert t['scrubs']['overview'].startswith(u'Scrubs es una divertida comedia') 350 | 351 | def test_multilanguage_selection(self): 352 | """Check selected language is used 353 | """ 354 | t_en = tvdb_api.Tvdb(cache=get_test_cache_session(), language="en") 355 | t_it = tvdb_api.Tvdb(cache=get_test_cache_session(), language="it") 356 | 357 | assert t_en['dexter'][1][2]['episodeName'] == "Crocodile" 358 | assert t_it['dexter'][1][2]['episodeName'] == "Lacrime di coccodrillo" 359 | 360 | 361 | class TestTvdbUnicode: 362 | def test_search_in_chinese(self): 363 | """Check searching for show with language=zh returns Chinese seriesname 364 | """ 365 | t = tvdb_api.Tvdb(cache=get_test_cache_session(), language="zh") 366 | show = t[u'T\xecnh Ng\u01b0\u1eddi Hi\u1ec7n \u0110\u1ea1i'] 367 | assert type(show) == tvdb_api.Show 368 | assert show['seriesName'] == u'T\xecnh Ng\u01b0\u1eddi Hi\u1ec7n \u0110\u1ea1i' 369 | 370 | @pytest.mark.skip('Новое API не возвращает сразу все языки') 371 | def test_search_in_all_languages(self): 372 | """Check search_all_languages returns Chinese show, with language=en 373 | """ 374 | t = tvdb_api.Tvdb(cache=get_test_cache_session(), search_all_languages=True, language="en") 375 | show = t[u'T\xecnh Ng\u01b0\u1eddi Hi\u1ec7n \u0110\u1ea1i'] 376 | assert type(show) == tvdb_api.Show 377 | assert show['seriesName'] == u'Virtues Of Harmony II' 378 | 379 | 380 | class TestTvdbBanners: 381 | # Used to store the cached instance of Tvdb() 382 | t = None 383 | 384 | @classmethod 385 | def setup_class(cls): 386 | if cls.t is None: 387 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), banners=True) 388 | 389 | def test_have_banners(self): 390 | """Check banners at least one banner is found 391 | """ 392 | assert len(self.t['scrubs']['_banners']) > 0 393 | 394 | def test_banner_url(self): 395 | """Checks banner URLs start with http:// 396 | """ 397 | for banner_type, banner_data in self.t['scrubs']['_banners'].items(): 398 | for res, res_data in banner_data.items(): 399 | if res != 'raw': 400 | for bid, banner_info in res_data.items(): 401 | assert banner_info['_bannerpath'].startswith("http://") 402 | 403 | @pytest.mark.skip('В новом API нет картинки у эпизода') 404 | def test_episode_image(self): 405 | """Checks episode 'filename' image is fully qualified URL 406 | """ 407 | assert self.t['scrubs'][1][1]['filename'].startswith("http://") 408 | 409 | @pytest.mark.skip('В новом API у сериала кроме банера больше нет картинок') 410 | def test_show_artwork(self): 411 | """Checks various image URLs within season data are fully qualified 412 | """ 413 | for key in ['banner', 'fanart', 'poster']: 414 | assert self.t['scrubs'][key].startswith("http://") 415 | 416 | 417 | class TestTvdbActors: 418 | t = None 419 | 420 | @classmethod 421 | def setup_class(cls): 422 | if cls.t is None: 423 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), actors=True) 424 | 425 | def test_actors_is_correct_datatype(self): 426 | """Check show/_actors key exists and is correct type""" 427 | assert isinstance(self.t['scrubs']['_actors'], tvdb_api.Actors) 428 | 429 | def test_actors_has_actor(self): 430 | """Check show has at least one Actor 431 | """ 432 | assert isinstance(self.t['scrubs']['_actors'][0], tvdb_api.Actor) 433 | 434 | def test_actor_has_name(self): 435 | """Check first actor has a name""" 436 | names = [actor['name'] for actor in self.t['scrubs']['_actors']] 437 | 438 | assert u"Zach Braff" in names 439 | 440 | def test_actor_image_corrected(self): 441 | """Check image URL is fully qualified 442 | """ 443 | for actor in self.t['scrubs']['_actors']: 444 | if actor['image'] is not None: 445 | # Actor's image can be None, it displays as the placeholder 446 | # image on thetvdb.com 447 | assert actor['image'].startswith("http://") 448 | 449 | 450 | class TestTvdbDoctest: 451 | def test_doctest(self): 452 | """Check docstring examples works""" 453 | import doctest 454 | 455 | doctest.testmod(tvdb_api) 456 | 457 | 458 | class TestTvdbCustomCaching: 459 | def test_true_false_string(self): 460 | """Tests setting cache to True/False/string 461 | 462 | Basic tests, only checking for errors 463 | """ 464 | tvdb_api.Tvdb(cache=True) 465 | tvdb_api.Tvdb(cache=False) 466 | tvdb_api.Tvdb(cache="/tmp") 467 | 468 | def test_invalid_cache_option(self): 469 | """Tests setting cache to invalid value 470 | """ 471 | 472 | try: 473 | tvdb_api.Tvdb(cache=2.3) 474 | except ValueError: 475 | pass 476 | else: 477 | pytest.fail("Expected ValueError from setting cache to float") 478 | 479 | def test_custom_request_session(self): 480 | from requests import Session as OriginalSession 481 | 482 | class Used(Exception): 483 | pass 484 | 485 | class CustomCacheForTest(OriginalSession): 486 | call_count = 0 487 | 488 | def request(self, *args, **kwargs): 489 | raise Used("Hurray") 490 | 491 | c = CustomCacheForTest() 492 | t = tvdb_api.Tvdb(cache=c) 493 | try: 494 | t['scrubs'] 495 | except Used: 496 | pass 497 | else: 498 | pytest.fail("Did not use custom session") 499 | 500 | 501 | class TestTvdbById: 502 | t = None 503 | 504 | @classmethod 505 | def setup_class(cls): 506 | if cls.t is None: 507 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), actors=True) 508 | 509 | def test_actors_is_correct_datatype(self): 510 | """Check show/_actors key exists and is correct type""" 511 | assert self.t[76156]['seriesName'] == 'Scrubs' 512 | 513 | 514 | class TestTvdbShowOrdering: 515 | def test_ordering(self): 516 | """Test Tvdb.search method 517 | """ 518 | t_dvd = tvdb_api.Tvdb(cache=get_test_cache_session(), dvdorder=True) 519 | t_air = tvdb_api.Tvdb(cache=get_test_cache_session()) 520 | 521 | assert u'The Train Job' == t_air['Firefly'][1][1]['episodeName'] 522 | assert u'Serenity' == t_dvd['Firefly'][1][1]['episodeName'] 523 | 524 | assert ( 525 | u'The Cat and the Claw (1)' == t_air['Batman The Animated Series'][1][1]['episodeName'] 526 | ) 527 | assert u'On Leather Wings' == t_dvd['Batman The Animated Series'][1][1]['episodeName'] 528 | 529 | 530 | class TestTvdbShowSearch: 531 | # Used to store the cached instance of Tvdb() 532 | t = None 533 | 534 | @classmethod 535 | def setup_class(cls): 536 | if cls.t is None: 537 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session()) 538 | 539 | def test_search(self): 540 | """Test Tvdb.search method 541 | """ 542 | results = self.t.search("my name is earl") 543 | all_ids = [x['id'] for x in results] 544 | assert 75397 in all_ids 545 | 546 | 547 | class TestTvdbAltNames: 548 | t = None 549 | 550 | @classmethod 551 | def setup_class(cls): 552 | if cls.t is None: 553 | cls.t = tvdb_api.Tvdb(cache=get_test_cache_session(), actors=True) 554 | 555 | def test_1(self): 556 | """Tests basic access of series name alias 557 | """ 558 | results = self.t.search("Don't Trust the B---- in Apartment 23") 559 | series = results[0] 560 | assert 'Apartment 23' in series['aliases'] 561 | 562 | 563 | if __name__ == '__main__': 564 | cache = get_test_cache_session() 565 | t = tvdb_api.Tvdb(cache=cache) 566 | t['scrubs'][1][2] 567 | t = tvdb_api.Tvdb(cache=cache) 568 | t['scrubs'][1][2] 569 | # pytest.main() 570 | -------------------------------------------------------------------------------- /tvdb_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding:utf-8 3 | # author:dbr/Ben 4 | # project:tvdb_api 5 | # repository:http://github.com/dbr/tvdb_api 6 | # license:unlicense (http://unlicense.org/) 7 | 8 | """Simple-to-use Python interface to The TVDB's API (thetvdb.com) 9 | 10 | Example usage: 11 | 12 | >>> from tvdb_api import Tvdb 13 | >>> t = Tvdb() 14 | >>> t['Lost'][4][11]['episodeName'] 15 | u'Cabin Fever' 16 | """ 17 | 18 | __author__ = "dbr/Ben" 19 | __version__ = "3.1.0" 20 | 21 | 22 | import sys 23 | import os 24 | import time 25 | import types 26 | import getpass 27 | import tempfile 28 | import warnings 29 | import logging 30 | import hashlib 31 | 32 | import requests 33 | import requests_cache 34 | 35 | _DEFAULT_HEADERS = requests.utils.default_headers() 36 | 37 | def _to_bytes(s, encoding='utf-8'): 38 | return s if isinstance(s, bytes) else bytes(s, encoding) 39 | 40 | 41 | IS_PY2 = sys.version_info[0] == 2 42 | 43 | if IS_PY2: 44 | user_input = raw_input # noqa 45 | from urllib import quote as url_quote # noqa 46 | else: 47 | from urllib.parse import quote as url_quote 48 | 49 | user_input = input 50 | 51 | 52 | if IS_PY2: 53 | int_types = (int, long) # noqa 54 | text_type = unicode # noqa 55 | else: 56 | int_types = int 57 | text_type = str 58 | 59 | 60 | LOG = logging.getLogger("tvdb_api") 61 | 62 | 63 | # Exceptions 64 | 65 | 66 | class TvdbBaseException(Exception): 67 | """Base exception for all tvdb_api errors 68 | """ 69 | 70 | pass 71 | 72 | 73 | class TvdbError(TvdbBaseException): 74 | """An error with thetvdb.com (Cannot connect, for example) 75 | """ 76 | 77 | pass 78 | 79 | 80 | class TvdbUserAbort(TvdbBaseException): 81 | """User aborted the interactive selection (via 82 | the q command, ^c etc) 83 | """ 84 | 85 | pass 86 | 87 | 88 | class TvdbNotAuthorized(TvdbBaseException): 89 | """An authorization error with thetvdb.com 90 | """ 91 | 92 | pass 93 | 94 | 95 | class TvdbDataNotFound(TvdbBaseException): 96 | """Base for all attribute-not-found errors (e.gg missing show/season/episode/data) 97 | """ 98 | 99 | pass 100 | 101 | 102 | class TvdbShowNotFound(TvdbDataNotFound): 103 | """Show cannot be found on thetvdb.com (non-existent show) 104 | """ 105 | 106 | pass 107 | 108 | 109 | class TvdbSeasonNotFound(TvdbDataNotFound): 110 | """Season cannot be found on thetvdb.com 111 | """ 112 | 113 | pass 114 | 115 | 116 | class TvdbEpisodeNotFound(TvdbDataNotFound): 117 | """Episode cannot be found on thetvdb.com 118 | """ 119 | 120 | pass 121 | 122 | 123 | class TvdbResourceNotFound(TvdbDataNotFound): 124 | """Resource cannot be found on thetvdb.com 125 | """ 126 | 127 | pass 128 | 129 | 130 | class TvdbAttributeNotFound(TvdbDataNotFound): 131 | """Raised if an episode does not have the requested 132 | attribute (such as a episode name) 133 | """ 134 | 135 | pass 136 | 137 | 138 | # Backwards compatability re-bindings 139 | tvdb_exception = TvdbBaseException # Deprecated, for backwards compatability 140 | tvdb_error = TvdbError # Deprecated, for backwards compatability 141 | tvdb_userabort = TvdbUserAbort # Deprecated, for backwards compatability 142 | tvdb_notauthorized = TvdbNotAuthorized # Deprecated, for backwards compatability 143 | tvdb_shownotfound = TvdbShowNotFound # Deprecated, for backwards compatability 144 | tvdb_seasonnotfound = TvdbSeasonNotFound # Deprecated, for backwards compatability 145 | tvdb_episodenotfound = TvdbEpisodeNotFound # Deprecated, for backwards compatability 146 | tvdb_resourcenotfound = TvdbResourceNotFound # Deprecated, for backwards compatability 147 | tvdb_attributenotfound = TvdbAttributeNotFound # Deprecated, for backwards compatability 148 | 149 | tvdb_invalidlanguage = TvdbError # Unused/removed. This exists for backwards compatability. 150 | 151 | 152 | # UI 153 | 154 | 155 | class BaseUI(object): 156 | """Base user interface for Tvdb show selection. 157 | 158 | Selects first show. 159 | 160 | A UI is a callback. A class, it's __init__ function takes two arguments: 161 | 162 | - config, which is the Tvdb config dict, setup in tvdb_api.py 163 | - log, which is Tvdb's logger instance (which uses the logging module). You can 164 | call log.info() log.warning() etc 165 | 166 | It must have a method "selectSeries", this is passed a list of dicts, each dict 167 | contains the the keys "name" (human readable show name), and "sid" (the shows 168 | ID as on thetvdb.com). For example: 169 | 170 | [{'name': u'Lost', 'sid': u'73739'}, 171 | {'name': u'Lost Universe', 'sid': u'73181'}] 172 | 173 | The "selectSeries" method must return the appropriate dict, or it can raise 174 | tvdb_userabort (if the selection is aborted), tvdb_shownotfound (if the show 175 | cannot be found). 176 | 177 | A simple example callback, which returns a random series: 178 | 179 | >>> import random 180 | >>> from tvdb_ui import BaseUI 181 | >>> class RandomUI(BaseUI): 182 | ... def selectSeries(self, allSeries): 183 | ... import random 184 | ... return random.choice(allSeries) 185 | 186 | Then to use it.. 187 | 188 | >>> from tvdb_api import Tvdb 189 | >>> t = Tvdb(custom_ui = RandomUI) 190 | >>> random_matching_series = t['Lost'] 191 | >>> type(random_matching_series) 192 | 193 | """ 194 | 195 | def __init__(self, config, log=None): 196 | self.config = config 197 | if log is not None: 198 | warnings.warn( 199 | "the UI's log parameter is deprecated, instead use\n" 200 | "use import logging; logging.getLogger('ui').info('blah')\n" 201 | "The self.log attribute will be removed in the next version" 202 | ) 203 | self.log = logging.getLogger(__name__) 204 | 205 | def selectSeries(self, allSeries): 206 | return allSeries[0] 207 | 208 | 209 | class ConsoleUI(BaseUI): 210 | """Interactively allows the user to select a show from a console based UI 211 | """ 212 | 213 | def _displaySeries(self, allSeries, limit=6): 214 | """Helper function, lists series with corresponding ID 215 | """ 216 | if limit is not None: 217 | toshow = allSeries[:limit] 218 | else: 219 | toshow = allSeries 220 | 221 | print("TVDB Search Results:") 222 | for i, cshow in enumerate(toshow): 223 | i_show = i + 1 # Start at more human readable number 1 (not 0) 224 | LOG.debug('Showing allSeries[%s], series %s)' % (i_show, allSeries[i]['seriesName'])) 225 | if i == 0: 226 | extra = " (default)" 227 | else: 228 | extra = "" 229 | 230 | output = "%s -> %s [%s] # http://thetvdb.com/?tab=series&id=%s%s" % ( 231 | i_show, 232 | cshow['seriesName'], 233 | cshow['language'], 234 | str(cshow['id']), 235 | extra, 236 | ) 237 | if IS_PY2: 238 | print(output.encode("UTF-8", "ignore")) 239 | else: 240 | print(output) 241 | 242 | def selectSeries(self, allSeries): 243 | self._displaySeries(allSeries) 244 | 245 | if len(allSeries) == 1: 246 | # Single result, return it! 247 | print("Automatically selecting only result") 248 | return allSeries[0] 249 | 250 | if self.config['select_first'] is True: 251 | print("Automatically returning first search result") 252 | return allSeries[0] 253 | 254 | while True: # return breaks this loop 255 | try: 256 | print("Enter choice (first number, return for default, 'all', ? for help):") 257 | ans = user_input() 258 | except KeyboardInterrupt: 259 | raise tvdb_userabort("User aborted (^c keyboard interupt)") 260 | except EOFError: 261 | raise tvdb_userabort("User aborted (EOF received)") 262 | 263 | LOG.debug('Got choice of: %s' % (ans)) 264 | try: 265 | selected_id = int(ans) - 1 # The human entered 1 as first result, not zero 266 | except ValueError: # Input was not number 267 | if len(ans.strip()) == 0: 268 | # Default option 269 | LOG.debug('Default option, returning first series') 270 | return allSeries[0] 271 | if ans == "q": 272 | LOG.debug('Got quit command (q)') 273 | raise tvdb_userabort("User aborted ('q' quit command)") 274 | elif ans == "?": 275 | print("## Help") 276 | print("# Enter the number that corresponds to the correct show.") 277 | print("# a - display all results") 278 | print("# all - display all results") 279 | print("# ? - this help") 280 | print("# q - abort tvnamer") 281 | print("# Press return with no input to select first result") 282 | elif ans.lower() in ["a", "all"]: 283 | self._displaySeries(allSeries, limit=None) 284 | else: 285 | LOG.debug('Unknown keypress %s' % (ans)) 286 | else: 287 | LOG.debug('Trying to return ID: %d' % (selected_id)) 288 | try: 289 | return allSeries[selected_id] 290 | except IndexError: 291 | LOG.debug('Invalid show number entered!') 292 | print("Invalid number (%s) selected!") 293 | self._displaySeries(allSeries) 294 | 295 | 296 | # Main API 297 | 298 | 299 | class ShowContainer(dict): 300 | """Simple dict that holds a series of Show instances 301 | """ 302 | 303 | def __init__(self): 304 | self._stack = [] 305 | self._lastgc = time.time() 306 | 307 | def __setitem__(self, key, value): 308 | self._stack.append(key) 309 | 310 | # keep only the 100th latest results 311 | if time.time() - self._lastgc > 20: 312 | for o in self._stack[:-100]: 313 | del self[o] 314 | self._stack = self._stack[-100:] 315 | 316 | self._lastgc = time.time() 317 | 318 | super(ShowContainer, self).__setitem__(key, value) 319 | 320 | 321 | class Show(dict): 322 | """Holds a dict of seasons, and show data. 323 | """ 324 | 325 | def __init__(self): 326 | dict.__init__(self) 327 | self.data = {} 328 | 329 | def __repr__(self): 330 | return "" % ( 331 | self.data.get(u'seriesName', 'instance'), 332 | len(self), 333 | ) 334 | 335 | def __getitem__(self, key): 336 | if key in self: 337 | # Key is an episode, return it 338 | return dict.__getitem__(self, key) 339 | 340 | if key in self.data: 341 | # Non-numeric request is for show-data 342 | return dict.__getitem__(self.data, key) 343 | 344 | # Data wasn't found, raise appropriate error 345 | if isinstance(key, int) or key.isdigit(): 346 | # Episode number x was not found 347 | raise tvdb_seasonnotfound("Could not find season %s" % (repr(key))) 348 | else: 349 | # If it's not numeric, it must be an attribute name, which 350 | # doesn't exist, so attribute error. 351 | raise tvdb_attributenotfound("Cannot find attribute %s" % (repr(key))) 352 | 353 | def aired_on(self, date): 354 | ret = self.search(str(date), 'firstAired') 355 | if len(ret) == 0: 356 | raise tvdb_episodenotfound("Could not find any episodes that aired on %s" % date) 357 | return ret 358 | 359 | def search(self, term=None, key=None): 360 | """ 361 | Search all episodes in show. Can search all data, or a specific key 362 | (for example, episodename) 363 | 364 | Always returns an array (can be empty). First index contains the first 365 | match, and so on. 366 | 367 | Each array index is an Episode() instance, so doing 368 | search_results[0]['episodename'] will retrieve the episode name of the 369 | first match. 370 | 371 | Search terms are converted to lower case (unicode) strings. 372 | 373 | # Examples 374 | 375 | These examples assume t is an instance of Tvdb(): 376 | 377 | >>> t = Tvdb() 378 | >>> 379 | 380 | To search for all episodes of Scrubs with a bit of data 381 | containing "my first day": 382 | 383 | >>> t['Scrubs'].search("my first day") 384 | [] 385 | >>> 386 | 387 | Search for "My Name Is Earl" episode named "Faked His Own Death": 388 | 389 | >>> t['My Name Is Earl'].search('Faked My Own Death', key='episodeName') 390 | [] 391 | >>> 392 | 393 | To search Scrubs for all episodes with "mentor" in the episode name: 394 | 395 | >>> t['scrubs'].search('mentor', key='episodeName') 396 | [, ] 397 | >>> 398 | 399 | # Using search results 400 | 401 | >>> results = t['Scrubs'].search("my first") 402 | >>> print results[0]['episodeName'] 403 | My First Day 404 | >>> for x in results: print x['episodeName'] 405 | My First Day 406 | My First Step 407 | My First Kill 408 | >>> 409 | """ 410 | results = [] 411 | for cur_season in self.values(): 412 | searchresult = cur_season.search(term=term, key=key) 413 | if len(searchresult) != 0: 414 | results.extend(searchresult) 415 | 416 | return results 417 | 418 | 419 | class Season(dict): 420 | def __init__(self, show=None): 421 | """The show attribute points to the parent show 422 | """ 423 | self.show = show 424 | 425 | def __repr__(self): 426 | return "" % (len(self.keys())) 427 | 428 | def __getitem__(self, episode_number): 429 | if episode_number not in self: 430 | raise tvdb_episodenotfound("Could not find episode %s" % (repr(episode_number))) 431 | else: 432 | return dict.__getitem__(self, episode_number) 433 | 434 | def search(self, term=None, key=None): 435 | """Search all episodes in season, returns a list of matching Episode 436 | instances. 437 | 438 | >>> t = Tvdb() 439 | >>> t['scrubs'][1].search('first day') 440 | [] 441 | >>> 442 | 443 | See Show.search documentation for further information on search 444 | """ 445 | results = [] 446 | for ep in self.values(): 447 | searchresult = ep.search(term=term, key=key) 448 | if searchresult is not None: 449 | results.append(searchresult) 450 | return results 451 | 452 | 453 | class Episode(dict): 454 | def __init__(self, season=None): 455 | """The season attribute points to the parent season 456 | """ 457 | self.season = season 458 | 459 | def __repr__(self): 460 | seasno = self.get(u'airedSeason', 0) 461 | epno = self.get(u'airedEpisodeNumber', 0) 462 | epname = self.get(u'episodeName') 463 | if epname is not None: 464 | return "" % (seasno, epno, epname) 465 | else: 466 | return "" % (seasno, epno) 467 | 468 | def __getitem__(self, key): 469 | try: 470 | return dict.__getitem__(self, key) 471 | except KeyError: 472 | raise tvdb_attributenotfound("Cannot find attribute %s" % (repr(key))) 473 | 474 | def search(self, term=None, key=None): 475 | """Search episode data for term, if it matches, return the Episode (self). 476 | The key parameter can be used to limit the search to a specific element, 477 | for example, episodename. 478 | 479 | This primarily for use use by Show.search and Season.search. See 480 | Show.search for further information on search 481 | 482 | Simple example: 483 | 484 | >>> e = Episode() 485 | >>> e['episodeName'] = "An Example" 486 | >>> e.search("examp") 487 | 488 | >>> 489 | 490 | Limiting by key: 491 | 492 | >>> e.search("examp", key = "episodeName") 493 | 494 | >>> 495 | """ 496 | if term is None: 497 | raise TypeError("must supply string to search for (contents)") 498 | 499 | term = text_type(term).lower() 500 | for cur_key, cur_value in self.items(): 501 | cur_key = text_type(cur_key) 502 | cur_value = text_type(cur_value).lower() 503 | if key is not None and cur_key != key: 504 | # Do not search this key 505 | continue 506 | if cur_value.find(text_type(term)) > -1: 507 | return self 508 | 509 | 510 | class Actors(list): 511 | """Holds all Actor instances for a show 512 | """ 513 | 514 | pass 515 | 516 | 517 | class Actor(dict): 518 | """Represents a single actor. Should contain.. 519 | 520 | id, 521 | image, 522 | name, 523 | role, 524 | sortorder 525 | """ 526 | 527 | def __repr__(self): 528 | return "" % self.get("name") 529 | 530 | 531 | def create_key(self, request): 532 | """A new cache_key algo is required as the authentication token 533 | changes with each run. Also there are other header params which 534 | also change with each request (e.g. timestamp). Excluding all 535 | headers means that Accept-Language is excluded which means 536 | different language requests will return the cached response from 537 | the wrong language. 538 | 539 | The _loadurl part checks the cache before a get is performed so 540 | that an auth token can be obtained. If the response is already in 541 | the cache, the auth token is not required. This prevents the need 542 | to do a get which may access the host and fail because the session 543 | is not yet not authorized. It is not necessary to authorize if the 544 | cache is to be used thus saving host and network traffic. 545 | """ 546 | 547 | if self._ignored_parameters: 548 | url, body = self._remove_ignored_parameters(request) 549 | else: 550 | url, body = request.url, request.body 551 | key = hashlib.sha256() 552 | key.update(_to_bytes(request.method.upper())) 553 | key.update(_to_bytes(url)) 554 | if request.body: 555 | key.update(_to_bytes(body)) 556 | else: 557 | if self._include_get_headers and request.headers != _DEFAULT_HEADERS: 558 | for name, value in sorted(request.headers.items()): 559 | # include only Accept-Language as it is important for context 560 | if name in ['Accept-Language']: 561 | key.update(_to_bytes(name)) 562 | key.update(_to_bytes(value)) 563 | return key.hexdigest() 564 | 565 | 566 | class Tvdb: 567 | """Create easy-to-use interface to name of season/episode name 568 | >>> t = Tvdb() 569 | >>> t['Scrubs'][1][24]['episodeName'] 570 | u'My Last Day' 571 | """ 572 | 573 | def __init__( 574 | self, 575 | interactive=False, 576 | select_first=False, 577 | cache=True, 578 | banners=False, 579 | actors=False, 580 | custom_ui=None, 581 | language=None, 582 | search_all_languages=False, 583 | apikey=None, 584 | username=None, 585 | userkey=None, 586 | forceConnect=None, # noqa 587 | dvdorder=False, 588 | ): 589 | 590 | """interactive (True/False): 591 | When True, uses built-in console UI is used to select the correct show. 592 | When False, the first search result is used. 593 | 594 | select_first (True/False): 595 | Automatically selects the first series search result (rather 596 | than showing the user a list of more than one series). 597 | Is overridden by interactive = False, or specifying a custom_ui 598 | 599 | cache (True/False/str/requests_cache.CachedSession): 600 | 601 | Retrieved URLs can be persisted to to disc. 602 | 603 | True/False enable or disable default caching. Passing 604 | string specifies the directory where to store the 605 | "tvdb.sqlite3" cache file. Alternatively a custom 606 | requests.Session instance can be passed (e.g maybe a 607 | customised instance of `requests_cache.CachedSession`) 608 | 609 | banners (True/False): 610 | Retrieves the banners for a show. These are accessed 611 | via the _banners key of a Show(), for example: 612 | 613 | >>> Tvdb(banners=True)['scrubs']['_banners'].keys() 614 | [u'fanart', u'poster', u'seasonwide', u'season', u'series'] 615 | 616 | actors (True/False): 617 | Retrieves a list of the actors for a show. These are accessed 618 | via the _actors key of a Show(), for example: 619 | 620 | >>> t = Tvdb(actors=True) 621 | >>> t['scrubs']['_actors'][0]['name'] 622 | u'John C. McGinley' 623 | 624 | custom_ui (tvdb_ui.BaseUI subclass): 625 | A callable subclass of tvdb_ui.BaseUI (overrides interactive option) 626 | 627 | language (2 character language abbreviation): 628 | The 2 digit language abbreviation used for the returned data, 629 | and is also used when searching. For a complete list, call 630 | the `Tvdb.available_languages` method. 631 | Default is "en" (English). 632 | 633 | search_all_languages (True/False): 634 | By default, Tvdb will only search in the language specified using 635 | the language option. When this is True, it will search for the 636 | show in and language 637 | 638 | apikey (str/unicode): 639 | Your API key for TheTVDB. You can easily register a key with in 640 | a few minutes: 641 | https://thetvdb.com/api-information 642 | 643 | username (str/unicode or None): 644 | Specify a user account to use for actions which require 645 | authentication (e.g marking a series as favourite, submitting ratings) 646 | 647 | userkey (str/unicode, or None): 648 | User authentication key relating to "username". 649 | 650 | forceConnect: 651 | DEPRECATED. Disabled the timeout-throttling logic. Now has no function 652 | """ 653 | 654 | if forceConnect is not None: 655 | warnings.warn( 656 | "forceConnect argument is deprecated and will be removed soon", 657 | category=DeprecationWarning, 658 | ) 659 | 660 | self.shows = ShowContainer() # Holds all Show classes 661 | self.corrections = {} # Holds show-name to show_id mapping 662 | 663 | self.config = {} 664 | 665 | # Ability to pull key form env-var mostly for unit-tests 666 | _test_key = os.getenv('TVDB_API_KEY') 667 | if apikey is None and _test_key is not None: 668 | apikey = _test_key 669 | 670 | if apikey is None: 671 | raise ValueError( 672 | ( 673 | "apikey argument is now required - an API key can be easily registered " 674 | "at https://thetvdb.com/api-information" 675 | ) 676 | ) 677 | self.config['auth_payload'] = { 678 | "apikey": apikey, 679 | "username": username or "", 680 | "userkey": userkey or "", 681 | } 682 | 683 | self.config['custom_ui'] = custom_ui 684 | 685 | self.config['interactive'] = interactive # prompt for correct series? 686 | 687 | self.config['select_first'] = select_first 688 | 689 | self.config['search_all_languages'] = search_all_languages 690 | 691 | self.config['dvdorder'] = dvdorder 692 | 693 | if cache is True: 694 | cache_dir = self._getTempDir() 695 | LOG.debug("Caching using requests_cache to %s" % cache_dir) 696 | self.session = requests_cache.CachedSession( 697 | expire_after=21600, # 6 hours 698 | backend='sqlite', 699 | cache_name=cache_dir, 700 | include_get_headers=True, 701 | ) 702 | self.session.cache.create_key = types.MethodType(create_key, self.session.cache) 703 | self.session.remove_expired_responses() 704 | self.config['cache_enabled'] = True 705 | elif cache is False: 706 | LOG.debug("Caching disabled") 707 | self.session = requests.Session() 708 | self.config['cache_enabled'] = False 709 | elif isinstance(cache, str): 710 | LOG.debug("Caching using requests_cache to specified directory %s" % cache) 711 | # Specified cache path 712 | self.session = requests_cache.CachedSession( 713 | expire_after=21600, # 6 hours 714 | backend='sqlite', 715 | cache_name=os.path.join(cache, "tvdb_api"), 716 | include_get_headers=True, 717 | ) 718 | self.session.cache.create_key = types.MethodType(create_key, self.session.cache) 719 | self.session.remove_expired_responses() 720 | else: 721 | LOG.debug("Using specified requests.Session") 722 | self.session = cache 723 | try: 724 | self.session.get 725 | except AttributeError: 726 | raise ValueError( 727 | ( 728 | "cache argument must be True/False, string as cache path " 729 | "or requests.Session-type object (e.g from requests_cache.CachedSession)" 730 | ) 731 | ) 732 | 733 | self.config['banners_enabled'] = banners 734 | self.config['actors_enabled'] = actors 735 | 736 | if language is None: 737 | self.config['language'] = 'en' 738 | else: 739 | self.config['language'] = language 740 | 741 | # The following url_ configs are based of the 742 | # https://api.thetvdb.com/swagger 743 | self.config['base_url'] = "http://thetvdb.com" 744 | self.config['api_url'] = "https://api.thetvdb.com" 745 | 746 | self.config['url_getSeries'] = u"%(api_url)s/search/series?name=%%s" % self.config 747 | 748 | self.config['url_epInfo'] = u"%(api_url)s/series/%%s/episodes" % self.config 749 | 750 | self.config['url_seriesInfo'] = u"%(api_url)s/series/%%s" % self.config 751 | self.config['url_actorsInfo'] = u"%(api_url)s/series/%%s/actors" % self.config 752 | 753 | self.config['url_seriesBanner'] = u"%(api_url)s/series/%%s/images" % self.config 754 | self.config['url_seriesBannerInfo'] = ( 755 | u"%(api_url)s/series/%%s/images/query?keyType=%%s" % self.config 756 | ) 757 | self.config['url_artworkPrefix'] = u"%(base_url)s/banners/%%s" % self.config 758 | 759 | self.__authorized = False 760 | self.headers = { 761 | 'Content-Type': 'application/json', 762 | 'Accept': 'application/json', 763 | 'Accept-Language': self.config['language'], 764 | } 765 | 766 | def _getTempDir(self): 767 | """Returns the [system temp dir]/tvdb_api-u501 (or 768 | tvdb_api-myuser) 769 | """ 770 | py_major = sys.version_info[ 771 | 0 772 | ] # Prefix with major version as 2 and 3 write incompatible caches 773 | if hasattr(os, 'getuid'): 774 | uid = "-u%d" % (os.getuid()) 775 | else: 776 | # For Windows 777 | uid = getpass.getuser() 778 | 779 | return os.path.join(tempfile.gettempdir(), "tvdb_api-%s-py%s" % (uid, py_major)) 780 | 781 | def _loadUrl(self, url, data=None, recache=False, language=None): 782 | """Return response from The TVDB API""" 783 | 784 | if not language: 785 | language = self.config['language'] 786 | self.headers['Accept-Language'] = language 787 | 788 | # TODO: Handle Exceptions 789 | # TODO: Update Token 790 | 791 | # encoded url is used for hashing in the cache so 792 | # python 2 and 3 generate the same hash 793 | if not self.__authorized: 794 | # only authorize of we haven't before and we 795 | # don't have the url in the cache 796 | fake_session_for_key = requests.Session() 797 | fake_session_for_key.headers['Accept-Language'] = language 798 | cache_key = None 799 | try: 800 | # in case the session class has no cache object, fail gracefully 801 | cache_key = self.session.cache.create_key( 802 | fake_session_for_key.prepare_request(requests.Request('GET', url)) 803 | ) 804 | except Exception: 805 | # FIXME: Can this just check for hasattr(self.session, "cache") instead? 806 | pass 807 | 808 | # fmt: off 809 | # No fmt because mangles noqa comment - https://github.com/psf/black/issues/195 810 | if not cache_key or not self.session.cache.has_key(cache_key): # noqa: not a dict, has_key is part of requests-cache API 811 | self.authorize() 812 | # fmt: on 813 | 814 | response = self.session.get(url, headers=self.headers) 815 | r = response.json() 816 | LOG.debug("loadurl: %s language=%s" % (url, language)) 817 | LOG.debug("response:") 818 | LOG.debug(r) 819 | error = r.get('Error') 820 | errors = r.get('errors') 821 | r_data = r.get('data') 822 | links = r.get('links') 823 | 824 | if error: 825 | if error == u'Resource not found': 826 | # raise(tvdb_resourcenotfound) 827 | # handle no data at a different level so it is more specific 828 | pass 829 | elif error.lower() == u'not authorized': 830 | # Note: Error string sometimes comes back as "Not authorized" or "Not Authorized" 831 | raise tvdb_notauthorized() 832 | elif error.startswith(u"ID: ") and error.endswith("not found"): 833 | # FIXME: Refactor error out of in this method 834 | raise tvdb_shownotfound("%s" % error) 835 | else: 836 | raise tvdb_error("%s" % error) 837 | 838 | if errors: 839 | if errors and u'invalidLanguage' in errors: 840 | # raise(tvdb_invalidlanguage(errors[u'invalidLanguage'])) 841 | # invalidLanguage does not mean there is no data 842 | # there is just less data (missing translations) 843 | pass 844 | 845 | if data and isinstance(data, list): 846 | data.extend(r_data) 847 | else: 848 | data = r_data 849 | 850 | if links and links['next']: 851 | url = url.split('?')[0] 852 | _url = url + "?page=%s" % links['next'] 853 | self._loadUrl(_url, data) 854 | 855 | return data 856 | 857 | def authorize(self): 858 | LOG.debug("auth") 859 | r = self.session.post( 860 | 'https://api.thetvdb.com/login', json=self.config['auth_payload'], headers=self.headers 861 | ) 862 | r_json = r.json() 863 | error = r_json.get('Error') 864 | if error: 865 | if error == u'Not Authorized': 866 | raise (tvdb_notauthorized) 867 | token = r_json.get('token') 868 | self.headers['Authorization'] = "Bearer %s" % text_type(token) 869 | self.__authorized = True 870 | 871 | def _getetsrc(self, url, language=None): 872 | """Loads a URL using caching, returns an ElementTree of the source 873 | """ 874 | src = self._loadUrl(url, language=language) 875 | 876 | return src 877 | 878 | def _setItem(self, sid, seas, ep, attrib, value): 879 | """Creates a new episode, creating Show(), Season() and 880 | Episode()s as required. Called by _getShowData to populate show 881 | 882 | Since the nice-to-use tvdb[1][24]['name] interface 883 | makes it impossible to do tvdb[1][24]['name] = "name" 884 | and still be capable of checking if an episode exists 885 | so we can raise tvdb_shownotfound, we have a slightly 886 | less pretty method of setting items.. but since the API 887 | is supposed to be read-only, this is the best way to 888 | do it! 889 | The problem is that calling tvdb[1][24]['episodename'] = "name" 890 | calls __getitem__ on tvdb[1], there is no way to check if 891 | tvdb.__dict__ should have a key "1" before we auto-create it 892 | """ 893 | if sid not in self.shows: 894 | self.shows[sid] = Show() 895 | if seas not in self.shows[sid]: 896 | self.shows[sid][seas] = Season(show=self.shows[sid]) 897 | if ep not in self.shows[sid][seas]: 898 | self.shows[sid][seas][ep] = Episode(season=self.shows[sid][seas]) 899 | self.shows[sid][seas][ep][attrib] = value 900 | 901 | def _setShowData(self, sid, key, value): 902 | """Sets self.shows[sid] to a new Show instance, or sets the data 903 | """ 904 | if sid not in self.shows: 905 | self.shows[sid] = Show() 906 | self.shows[sid].data[key] = value 907 | 908 | def search(self, series): 909 | """This searches TheTVDB.com for the series name 910 | and returns the result list 911 | """ 912 | series = url_quote(series.encode("utf-8")) 913 | LOG.debug("Searching for show %s" % series) 914 | series_resp = self._getetsrc(self.config['url_getSeries'] % (series)) 915 | if not series_resp: 916 | LOG.debug('Series result returned zero') 917 | raise tvdb_shownotfound( 918 | "Show-name search returned zero results (cannot find show on TVDB)" 919 | ) 920 | 921 | all_series = [] 922 | for series in series_resp: 923 | series['language'] = self.config['language'] 924 | LOG.debug('Found series %(seriesName)s' % series) 925 | all_series.append(series) 926 | 927 | return all_series 928 | 929 | def _getSeries(self, series): 930 | """This searches TheTVDB.com for the series name, 931 | If a custom_ui UI is configured, it uses this to select the correct 932 | series. If not, and interactive == True, ConsoleUI is used, if not 933 | BaseUI is used to select the first result. 934 | """ 935 | all_series = self.search(series) 936 | 937 | if self.config['custom_ui'] is not None: 938 | LOG.debug("Using custom UI %s" % (repr(self.config['custom_ui']))) 939 | ui = self.config['custom_ui'](config=self.config) 940 | else: 941 | if not self.config['interactive']: 942 | LOG.debug('Auto-selecting first search result using BaseUI') 943 | ui = BaseUI(config=self.config) 944 | else: 945 | LOG.debug('Interactively selecting show using ConsoleUI') 946 | ui = ConsoleUI(config=self.config) 947 | 948 | return ui.selectSeries(all_series) 949 | 950 | def available_languages(self): 951 | """Returns a list of the available language abbreviations 952 | which can be used in Tvdb(language="...") etc 953 | """ 954 | et = self._getetsrc("https://api.thetvdb.com/languages") 955 | languages = [x['abbreviation'] for x in et] 956 | return sorted(languages) 957 | 958 | def _parseBanners(self, sid): 959 | """Parses banners XML, from 960 | http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/banners.xml 961 | 962 | Banners are retrieved using t['show name]['_banners'], for example: 963 | 964 | >>> t = Tvdb(banners = True) 965 | >>> t['scrubs']['_banners'].keys() 966 | [u'fanart', u'poster', u'seasonwide', u'season', u'series'] 967 | >>> t['scrubs']['_banners']['poster']['680x1000'][35308]['_bannerpath'] 968 | u'http://thetvdb.com/banners/posters/76156-2.jpg' 969 | >>> 970 | 971 | Any key starting with an underscore has been processed (not the raw 972 | data from the XML) 973 | 974 | This interface will be improved in future versions. 975 | """ 976 | LOG.debug('Getting season banners for %s' % (sid)) 977 | banners_resp = self._getetsrc(self.config['url_seriesBanner'] % sid) 978 | banners = {} 979 | for cur_banner in banners_resp.keys(): 980 | banners_info = self._getetsrc(self.config['url_seriesBannerInfo'] % (sid, cur_banner)) 981 | for banner_info in banners_info: 982 | bid = banner_info.get('id') 983 | btype = banner_info.get('keyType') 984 | btype2 = banner_info.get('resolution') 985 | if btype is None or btype2 is None: 986 | continue 987 | 988 | if btype not in banners: 989 | banners[btype] = {} 990 | if btype2 not in banners[btype]: 991 | banners[btype][btype2] = {} 992 | if bid not in banners[btype][btype2]: 993 | banners[btype][btype2][bid] = {} 994 | 995 | banners[btype][btype2][bid]['bannerpath'] = banner_info['fileName'] 996 | banners[btype][btype2][bid]['resolution'] = banner_info['resolution'] 997 | banners[btype][btype2][bid]['subKey'] = banner_info['subKey'] 998 | 999 | for k, v in list(banners[btype][btype2][bid].items()): 1000 | if k.endswith("path"): 1001 | new_key = "_%s" % k 1002 | LOG.debug("Transforming %s to %s" % (k, new_key)) 1003 | new_url = self.config['url_artworkPrefix'] % v 1004 | banners[btype][btype2][bid][new_key] = new_url 1005 | 1006 | banners[btype]['raw'] = banners_info 1007 | self._setShowData(sid, "_banners", banners) 1008 | 1009 | def _parseActors(self, sid): 1010 | """Parsers actors XML, from 1011 | http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/actors.xml 1012 | 1013 | Actors are retrieved using t['show name]['_actors'], for example: 1014 | 1015 | >>> t = Tvdb(actors = True) 1016 | >>> actors = t['scrubs']['_actors'] 1017 | >>> type(actors) 1018 | 1019 | >>> type(actors[0]) 1020 | 1021 | >>> actors[0] 1022 | 1023 | >>> sorted(actors[0].keys()) 1024 | [u'id', u'image', u'imageAdded', u'imageAuthor', u'lastUpdated', u'name', u'role', 1025 | u'seriesId', u'sortOrder'] 1026 | >>> actors[0]['name'] 1027 | u'John C. McGinley' 1028 | >>> actors[0]['image'] 1029 | u'http://thetvdb.com/banners/actors/43638.jpg' 1030 | 1031 | Any key starting with an underscore has been processed (not the raw 1032 | data from the XML) 1033 | """ 1034 | LOG.debug("Getting actors for %s" % (sid)) 1035 | actors_resp = self._getetsrc(self.config['url_actorsInfo'] % (sid)) 1036 | 1037 | cur_actors = Actors() 1038 | for cur_actor_item in actors_resp: 1039 | cur_actor = Actor() 1040 | for tag, value in cur_actor_item.items(): 1041 | if value is not None: 1042 | if tag == "image": 1043 | value = self.config['url_artworkPrefix'] % (value) 1044 | cur_actor[tag] = value 1045 | cur_actors.append(cur_actor) 1046 | self._setShowData(sid, '_actors', cur_actors) 1047 | 1048 | def _getShowData(self, sid, language): 1049 | """Takes a series ID, gets the epInfo URL and parses the TVDB 1050 | XML file into the shows dict in layout: 1051 | shows[series_id][season_number][episode_number] 1052 | """ 1053 | 1054 | if self.config['language'] is None: 1055 | LOG.debug('Config language is none, using show language') 1056 | if language is None: 1057 | raise tvdb_error("config['language'] was None, this should not happen") 1058 | else: 1059 | LOG.debug( 1060 | 'Configured language %s override show language of %s' 1061 | % (self.config['language'], language) 1062 | ) 1063 | 1064 | # Parse show information 1065 | LOG.debug('Getting all series data for %s' % (sid)) 1066 | series_info_resp = self._getetsrc(self.config['url_seriesInfo'] % sid) 1067 | for tag, value in series_info_resp.items(): 1068 | if value is not None: 1069 | if tag in ['banner', 'fanart', 'poster']: 1070 | value = self.config['url_artworkPrefix'] % (value) 1071 | 1072 | self._setShowData(sid, tag, value) 1073 | # set language 1074 | self._setShowData(sid, u'language', self.config['language']) 1075 | 1076 | # Parse banners 1077 | if self.config['banners_enabled']: 1078 | self._parseBanners(sid) 1079 | 1080 | # Parse actors 1081 | if self.config['actors_enabled']: 1082 | self._parseActors(sid) 1083 | 1084 | # Parse episode data 1085 | LOG.debug('Getting all episodes of %s' % (sid)) 1086 | 1087 | url = self.config['url_epInfo'] % sid 1088 | 1089 | eps_resp = self._getetsrc(url, language=language) 1090 | 1091 | for cur_ep in eps_resp: 1092 | 1093 | if self.config['dvdorder']: 1094 | LOG.debug('Using DVD ordering.') 1095 | use_dvd = ( 1096 | cur_ep.get('dvdSeason') is not None 1097 | and cur_ep.get('dvdEpisodeNumber') is not None 1098 | ) 1099 | else: 1100 | use_dvd = False 1101 | 1102 | if use_dvd: 1103 | elem_seasnum, elem_epno = cur_ep.get('dvdSeason'), cur_ep.get('dvdEpisodeNumber') 1104 | else: 1105 | elem_seasnum, elem_epno = cur_ep['airedSeason'], cur_ep['airedEpisodeNumber'] 1106 | 1107 | if elem_seasnum is None or elem_epno is None: 1108 | LOG.warning( 1109 | "An episode has incomplete season/episode number (season: %r, episode: %r)" 1110 | % (elem_seasnum, elem_epno) 1111 | ) 1112 | # TODO: Should this happen? 1113 | continue # Skip to next episode 1114 | 1115 | seas_no = elem_seasnum 1116 | ep_no = elem_epno 1117 | 1118 | for cur_item in cur_ep.keys(): 1119 | tag = cur_item 1120 | value = cur_ep[cur_item] 1121 | if value is not None: 1122 | if tag == 'filename': 1123 | value = self.config['url_artworkPrefix'] % (value) 1124 | self._setItem(sid, seas_no, ep_no, tag, value) 1125 | 1126 | def _nameToSid(self, name): 1127 | """Takes show name, returns the correct series ID (if the show has 1128 | already been grabbed), or grabs all episodes and returns 1129 | the correct SID. 1130 | """ 1131 | if name in self.corrections: 1132 | LOG.debug('Correcting %s to %s' % (name, self.corrections[name])) 1133 | sid = self.corrections[name] 1134 | else: 1135 | LOG.debug('Getting show %s' % name) 1136 | selected_series = self._getSeries(name) 1137 | sid = selected_series['id'] 1138 | LOG.debug('Got %(seriesName)s, id %(id)s' % selected_series) 1139 | 1140 | self.corrections[name] = sid 1141 | self._getShowData(selected_series['id'], self.config['language']) 1142 | 1143 | return sid 1144 | 1145 | def __getitem__(self, key): 1146 | """Handles tvdb_instance['seriesName'] calls. 1147 | The dict index should be the show id 1148 | """ 1149 | if isinstance(key, int_types): 1150 | sid = key 1151 | else: 1152 | sid = self._nameToSid(key) 1153 | LOG.debug('Got series id %s' % sid) 1154 | 1155 | if sid not in self.shows: 1156 | self._getShowData(sid, self.config['language']) 1157 | return self.shows[sid] 1158 | 1159 | def __repr__(self): 1160 | return repr(self.shows) 1161 | 1162 | 1163 | def main(): 1164 | """Simple example of using tvdb_api - it just 1165 | grabs an episode name interactively. 1166 | """ 1167 | import logging 1168 | 1169 | logging.basicConfig(level=logging.DEBUG) 1170 | 1171 | tvdb_instance = Tvdb(interactive=False, cache=False) 1172 | print(tvdb_instance['Lost']['seriesName']) 1173 | print(tvdb_instance['Lost'][1][4]['episodename']) 1174 | 1175 | 1176 | if __name__ == '__main__': 1177 | main() 1178 | --------------------------------------------------------------------------------