Skip to content

Commit

Permalink
cursepy can guess the download URL if none is provided #13
Browse files Browse the repository at this point in the history
  • Loading branch information
OwenCochell committed Nov 25, 2022
1 parent d808d77 commit 9f3eb59
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cursepy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

# Define some metadata here:

__version__ = '2.1.0'
__version__ = '2.2.0'
__author__ = 'Owen Cochell'
57 changes: 56 additions & 1 deletion cursepy/classes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ class CurseFile(BaseDownloader):
AWAITING_PUBLISHING = 14
FAILED_PUBLISHING = 15

CDN_URL = 'https://edge.forgecdn.net/files/'

INST_ID = 6

@property
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions docs/source/basic/curse_inst.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -629,6 +630,42 @@ object representing the addon this file is attached to.
The CurseFile class also has :ref:`download functionality<curse_download>`.
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
Expand Down
13 changes: 13 additions & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=====

Expand Down

0 comments on commit 9f3eb59

Please sign in to comment.