From 528689b5425b6ce0045f98bd1672bf7032f6d28d Mon Sep 17 00:00:00 2001 From: coldsofttech <161084795+coldsofttech@users.noreply.github.com> Date: Sun, 1 Sep 2024 19:10:02 +0100 Subject: [PATCH] Updated "download_master_playlist" to return JSON-formatted available resolutions --- CHANGELOG.md | 3 ++- README.md | 13 ++++++++++++- SECURITY.md | 2 +- TROUBLESHOOTING.md | 24 +++++++++--------------- pym3u8downloader/__init__.py | 5 +++-- pym3u8downloader/downloader.py | 28 ++++++++++------------------ pym3u8downloader/exceptions.py | 28 +++++++++++++++++++++++++++- tests/test_m3u8downloader.py | 5 ++++- 8 files changed, 68 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0072e26..d881ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Version History -- 0.1.7: Restructured Code + Add. Test Cases (latest) +- 0.1.8: Updated "download_master_playlist" to return JSON-formatted available resolutions (latest) +- 0.1.7: Restructured Code + Add. Test Cases - 0.1.6: Fixed bug with SSL error - 0.1.5: Introduced Support for Master Playlist - 0.1.4: Added Additional Files Required for Master Playlist Tests diff --git a/README.md b/README.md index b495b6c..3b3e79c 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,23 @@ downloader.download_master_playlist(name='720') ### `M3U8DownloaderError` -This error class is employed to signal any issues or errors encountered during the execution of M3U8Downloader methods. +This error class is employed to signal any issues or errors encountered during the execution of `M3U8Downloader` +methods. #### Constructors - `M3U8DownloaderError(message: str)`: Initialize a M3U8DownloaderError. +### `M3U8DownloaderWarning` + +This warning class is employed to signal any issues encountered during the execution of the `download_master_playlist` +method of the `M3U8Downloader` class, especially when no parameters are passed. Along with the warning message, +the `json_data` variable is returned with all available resolution formats (variants) in JSON-structured format. + +#### Constructors + +- `M3U8DownloaderWarning(message: str, json_data: Optional[list] = None)`: Initialize a M3U8DownloaderWarning. + # Troubleshooting Guide For detailed troubleshooting guide, please refer to [TROUBLESHOOTING](TROUBLESHOOTING.md). diff --git a/SECURITY.md b/SECURITY.md index f75ee55..cc4ba3f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ version, which is currently: | Version | Supported | |---------|--------------------| -| 0.1.7 | :white_check_mark: | +| 0.1.8 | :white_check_mark: | If you are using an older version, we highly recommend upgrading to the latest version to ensure you have the latest security updates. diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index c69caf3..4c2e069 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -7,7 +7,7 @@ This document provides comprehensive guidance on troubleshooting issues related **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: Internet connection required. +pym3u8downloader.exceptions.M3U8DownloaderError: Internet connection required. ``` **Description:** @@ -24,7 +24,7 @@ To resolve this issue, ensure that you are connected to the internet and then re **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: Identified file "***" as master playlist. Please use "download_master_playlist" instead. +pym3u8downloader.exceptions.M3U8DownloaderError: Identified file "***" as master playlist. Please use "download_master_playlist" instead. ``` **Description:** @@ -52,7 +52,7 @@ downloader.download_master_playlist(name='720', bandwidth='2048', resolution='12 **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: Identified file "***" as playlist. Please use "download_playlist" instead. +pym3u8downloader.exceptions.M3U8DownloaderError: Identified file "***" as playlist. Please use "download_playlist" instead. ``` **Description:** @@ -80,7 +80,7 @@ downloader.download_playlist() **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: File "***" is not identified as either playlist or master. +pym3u8downloader.exceptions.M3U8DownloaderError: File "***" is not identified as either playlist or master. ``` **Description:** @@ -97,7 +97,7 @@ file link from someone else, contact them to ensure that they provide the correc **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: Unable to download "***" file. +pym3u8downloader.exceptions.M3U8DownloaderError: Unable to download "***" file. ``` **Description:** @@ -114,14 +114,8 @@ check that the file is accessible. Reattempt the download once these conditions **Error Message:** ```html -UserWarning: Identified * variants in the master playlist. To download the desired playlist, please provide additional parameters, such as NAME, BANDWIDTH, or RESOLUTION, to identify the specific variant. +pym3u8downloader.exceptions.M3U8DownloaderWarning: Identified * variants in the master playlist. To download the desired playlist, please provide additional parameters, such as NAME, BANDWIDTH, or RESOLUTION, to identify the specific variant. For example: use "download_master_playlist(name='720', bandwidth='2149280', resolution='1280x720')". - -You can view the available options using the following list: -[ -{'bandwidth': '***', 'name': '***', 'resolution': '***'}, -... -] ``` **Description:** @@ -132,13 +126,13 @@ package analyzes the master playlist and lists all available variants to assist **Solution:** -Review the list of available variants provided in the warning message. Choose the appropriate values for name, -bandwidth, and resolution, and then provide these parameters to download the desired video segments. +Review the list of available variants provided in the JSON-formatted return data. Choose the appropriate values for +name, bandwidth, and resolution, and then provide these parameters to download the desired video segments. **Error Message:** ```html -pym3u8downloader.__main__.M3U8DownloaderError: Selected variant, name="***", bandwidth="***", resolution="***" not found. +pym3u8downloader.exceptions.M3U8DownloaderError: Selected variant, name="***", bandwidth="***", resolution="***" not found. ``` **Description:** diff --git a/pym3u8downloader/__init__.py b/pym3u8downloader/__init__.py index 98c55c4..f0b2429 100644 --- a/pym3u8downloader/__init__.py +++ b/pym3u8downloader/__init__.py @@ -1,6 +1,7 @@ __all__ = [ "M3U8Downloader", "M3U8DownloaderError", + "M3U8DownloaderWarning", "__author__", "__description__", "__name__", @@ -13,7 +14,7 @@ into a single video file, and manage various error conditions. """ __name__ = "pym3u8downloader" -__version__ = "0.1.7" +__version__ = "0.1.8" from pym3u8downloader.downloader import M3U8Downloader -from pym3u8downloader.exceptions import M3U8DownloaderError +from pym3u8downloader.exceptions import M3U8DownloaderError, M3U8DownloaderWarning diff --git a/pym3u8downloader/downloader.py b/pym3u8downloader/downloader.py index 141e141..952e9d5 100644 --- a/pym3u8downloader/downloader.py +++ b/pym3u8downloader/downloader.py @@ -1,3 +1,4 @@ +import json import os import re import shutil @@ -7,7 +8,7 @@ from concurrent.futures import ThreadPoolExecutor from typing import Optional, TextIO, Union -from pym3u8downloader.exceptions import M3U8DownloaderError +from pym3u8downloader.exceptions import M3U8DownloaderError, M3U8DownloaderWarning from pym3u8downloader.utility_class import UtilityClass from pym3u8downloader.validations import validate_type @@ -830,23 +831,14 @@ def download_master_playlist( {k: v for k, v in variant.items() if k != 'uri'} for variant in variants ] - formatted_variants = '[\n' - for variant in display_variants: - formatted_variant = ' {' - for key, value in variant.items(): - formatted_variant += f"'{key}': '{value}', " - formatted_variant = formatted_variant.rstrip(', ') - formatted_variant += '},\n' - formatted_variants += formatted_variant - formatted_variants = formatted_variants.rstrip(',\n') + '\n]' - - raise UserWarning( - f'Identified {len(variants)} variants in the master playlist. ' - f'To download the desired playlist, please provide additional parameters, such as NAME, BANDWIDTH, ' - f'or RESOLUTION, to identify the specific variant.' - f'\nFor example: use "download_master_playlist(name=\'720\', bandwidth=\'2149280\', ' - f'resolution=\'1280x720\')".\n\n' - f'You can view the available options using the following list: \n{formatted_variants}' + formatted_variants = json.dumps(display_variants, indent=4) + + raise M3U8DownloaderWarning( + message=f'Identified {len(variants)} variants in the master playlist. To download the desired ' + f'playlist, please provide additional parameters, such as NAME, BANDWIDTH, or RESOLUTION, ' + f'to identify the specific variant.\nFor example: use "download_master_playlist(' + f'name=\'720\', bandwidth=\'2149280\', resolution=\'1280x720\')".', + json_data=json.loads(formatted_variants) ) else: selected_variant = self._search_playlist(variants, name, bandwidth, resolution) diff --git a/pym3u8downloader/exceptions.py b/pym3u8downloader/exceptions.py index f41c9ca..407e88a 100644 --- a/pym3u8downloader/exceptions.py +++ b/pym3u8downloader/exceptions.py @@ -1,3 +1,5 @@ +from typing import Optional, Union + from pym3u8downloader.validations import validate_type @@ -13,9 +15,33 @@ def __init__(self, message: str) -> None: """ Initialize a new instance of M3U8DownloaderError. - :param message: A human-readable error message describing the exception + :param message: A human-readable error message describing the exception. + :type message: str + """ + validate_type(message, str, 'message should be a string.') + self.message = message + super().__init__(self.message) + + +class M3U8DownloaderWarning(Warning): + """ + A warning raised by the M3U8Downloader class or its methods. + + This warning is used to indicate an issue with master playlist resolution that occurs during the operation of the + M3U8Downloader class or its methods. + """ + + def __init__(self, message: str, json_data: Optional[list] = None) -> None: + """ + Initialize a new instance of M3U8DownloaderWarning. + + :param message: A human-readable warning message describing the issue. :type message: str + :param json_data: The JSON-formatted data of all available resolutions from master playlist to choose from. + :type json_data: list """ validate_type(message, str, 'message should be a string.') + validate_type(json_data, Union[list, None], 'json_data should be a list.') self.message = message + self.json_data = json_data super().__init__(self.message) diff --git a/tests/test_m3u8downloader.py b/tests/test_m3u8downloader.py index 8bdbc90..46f5924 100644 --- a/tests/test_m3u8downloader.py +++ b/tests/test_m3u8downloader.py @@ -6,6 +6,7 @@ from commonclass import CommonClass from pym3u8downloader import M3U8Downloader, M3U8DownloaderError +from pym3u8downloader.exceptions import M3U8DownloaderWarning class TestM3U8Downloader(unittest.TestCase): @@ -606,8 +607,10 @@ def test_download_master_playlist_with_no_params(self): self.input_file_path = f'{CommonClass.get_git_test_parent_url()}/master.m3u8' downloader = M3U8Downloader(self.input_file_path, self.output_file_path) try: - with self.assertRaises(UserWarning): + with self.assertRaises(M3U8DownloaderWarning) as w: downloader.download_master_playlist() + self.assertIsNotNone(w.json_data) + self.assertGreater(len(w.json_data), 0) finally: try: downloader._remove_temp_directory()