diff --git a/cursepy/__init__.py b/cursepy/__init__.py index 5588110..9b76c8a 100644 --- a/cursepy/__init__.py +++ b/cursepy/__init__.py @@ -9,5 +9,5 @@ # Define some metadata here: -__version__ = '2.1.0' +__version__ = '2.2.0' __author__ = 'Owen Cochell' diff --git a/cursepy/classes/base.py b/cursepy/classes/base.py index 32f6e50..80f7a0f 100644 --- a/cursepy/classes/base.py +++ b/cursepy/classes/base.py @@ -543,6 +543,8 @@ class CurseFile(BaseDownloader): AWAITING_PUBLISHING = 14 FAILED_PUBLISHING = 15 + CDN_URL = 'https://edge.forgecdn.net/files/' + INST_ID = 6 @property @@ -645,6 +647,59 @@ def good_file(self) -> bool: return self.is_available and self.release_type == CurseFile.RELEASE and self.file_status == CurseFile.RELEASED + def guess_download(self) -> str: + """ + This method will attempt to guess the download URL. + + Some addons do not allow distribution on 3rd party services and APIs. + If this is the case, then the download URL will be 'None'. + This method will use available info to make a best guess URL for use. + + We do this by splitting up the file ID into parts of 4 + and merging some attributes together. + For example, if we have an id of '1234567' and a filename of + 'test.jar', we will get the following download URL: + + https://edge.forgecdn.net/files/1234/567/test.jar + + Please note, this method is experimental and might not work! + It is ALWAYS recommended to use the provided download URL, + if one is provided. + Also, this method will generate a URL for the official CurseForge CDN. + + Once you have this guess, you can set the 'download_url' parameter to the value + returned from this method, and download the file from there: + + .. code-block:: python + + file.download_url = file.guess_download() + file.download(PATH) + + Or, you can use this URL directly in the download operation: + + .. code-block:: python + + file.low_download(file.guess_download(), PATH) + + We use the 'low_download()' method, as it accepts a custom URL. + + :return: The best guess download URL + :rtype: str + """ + + download_url = CurseFile.CDN_URL + id = str(self.id) + + # Split up the file ID with 4 digits in each part: + + for i in range(0, len(id), 4): + + download_url += id[i:i+4] + '/' + + # Finally, add the filename: + + return download_url + self.file_name + @dataclass class CurseDependency(BaseCurseInstance): @@ -725,7 +780,7 @@ def file(self) -> CurseFile: :rtype: CurseFile """ - return self.hands.file(self,addon_id, self.file_id) + return self.hands.file(self.addon_id, self.file_id) @dataclass diff --git a/docs/source/basic/curse_inst.rst b/docs/source/basic/curse_inst.rst index 1f02f83..b8d1193 100644 --- a/docs/source/basic/curse_inst.rst +++ b/docs/source/basic/curse_inst.rst @@ -598,6 +598,7 @@ Our only understanding of the file is what the backend says it is. Production ready files could be poorly made, and non-production ready experimental files could also be valid. + To get the changelog of the file, you can use the 'changelog' property: @@ -629,6 +630,42 @@ object representing the addon this file is attached to. The CurseFile class also has :ref:`download functionality`. You can use the 'download()' method to download this file. +.. note:: + + This next section is only relevant to the official CurseForge API! + + If you aren't using the CurseForge backend, then this information + (probably) won't apply to you. + +In the official CurseForge API, addons can specify if they +are approved for distribution over 3rd party services. +Any projects created before the release of the official CurseForge API (around 2020-2021) +will have this enabled by default. +All new projects created afterwards will have this disabled by default. + +If 3rd party distribution is enabled, then the CurseForge API will serve a download +URL for each addon file. +Otherwise, the CurseForge API will simply server 'None', and the 'download()' method will fail. +You can get around this by using the 'guess_download()' method: + +.. code-block:: python + + url = inst.guess_download() + +This method uses some attributes to create a best guess download URL that may work +(more testing is required!). +This URL will download the addon files from the official CurseForge Content Distribution Network, +regardless of the handler that retrieved the data. + +It is highly recommended to use a download URL provided by the backend if possible! + +Once you have the URL, you can set the 'download_url' parameter and then download the file: + +.. code-block:: python + + inst.download_url = inst.guess_download() + inst.download() + .. _curse_dependency: CurseDependency diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 8605dda..8a1fe54 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -2,6 +2,19 @@ Changelog ========= +2.2.0 +===== + +Features Added +-------------- + +* CurseFile can now generate a guess download URL if the backend does not serve a valid download URL + +Bug Fixes +--------- + +* Fixed a syntax error while getting the file a dependency is apart of + 2.1.0 =====