quasarr 1.29.0__py3-none-any.whl → 1.31.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of quasarr might be problematic. Click here for more details.

@@ -0,0 +1,131 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Quasarr
3
+ # Project by https://github.com/rix1337
4
+
5
+ from quasarr.providers.myjd_api import TokenExpiredException, RequestTimeoutException, MYJDException
6
+
7
+
8
+ class JDPackageCache:
9
+ """
10
+ Caches JDownloader package/link queries within a single request.
11
+
12
+ IMPORTANT: This cache is ONLY valid for the duration of ONE get_packages()
13
+ or delete_package() call. JDownloader state can be modified at any time by
14
+ the user or third-party tools, so cached data must NEVER persist across
15
+ separate requests.
16
+
17
+ This reduces redundant API calls within a single operation where the same
18
+ data (e.g., linkgrabber_links) is needed multiple times.
19
+
20
+ Usage:
21
+ # Cache is created and discarded within a single function call
22
+ cache = JDPackageCache(device)
23
+ packages = cache.linkgrabber_packages # Fetches from API
24
+ packages = cache.linkgrabber_packages # Returns cached (same request)
25
+ # Cache goes out of scope and is garbage collected
26
+ """
27
+
28
+ def __init__(self, device):
29
+ self._device = device
30
+ self._linkgrabber_packages = None
31
+ self._linkgrabber_links = None
32
+ self._downloader_packages = None
33
+ self._downloader_links = None
34
+ self._archive_package_uuids = None # Set of package UUIDs containing archives
35
+ self._is_collecting = None
36
+
37
+ @property
38
+ def linkgrabber_packages(self):
39
+ if self._linkgrabber_packages is None:
40
+ try:
41
+ self._linkgrabber_packages = self._device.linkgrabber.query_packages()
42
+ except (TokenExpiredException, RequestTimeoutException, MYJDException):
43
+ self._linkgrabber_packages = []
44
+ return self._linkgrabber_packages
45
+
46
+ @property
47
+ def linkgrabber_links(self):
48
+ if self._linkgrabber_links is None:
49
+ try:
50
+ self._linkgrabber_links = self._device.linkgrabber.query_links()
51
+ except (TokenExpiredException, RequestTimeoutException, MYJDException):
52
+ self._linkgrabber_links = []
53
+ return self._linkgrabber_links
54
+
55
+ @property
56
+ def downloader_packages(self):
57
+ if self._downloader_packages is None:
58
+ try:
59
+ self._downloader_packages = self._device.downloads.query_packages()
60
+ except (TokenExpiredException, RequestTimeoutException, MYJDException):
61
+ self._downloader_packages = []
62
+ return self._downloader_packages
63
+
64
+ @property
65
+ def downloader_links(self):
66
+ if self._downloader_links is None:
67
+ try:
68
+ self._downloader_links = self._device.downloads.query_links()
69
+ except (TokenExpiredException, RequestTimeoutException, MYJDException):
70
+ self._downloader_links = []
71
+ return self._downloader_links
72
+
73
+ @property
74
+ def is_collecting(self):
75
+ if self._is_collecting is None:
76
+ try:
77
+ self._is_collecting = self._device.linkgrabber.is_collecting()
78
+ except (TokenExpiredException, RequestTimeoutException, MYJDException):
79
+ self._is_collecting = False
80
+ return self._is_collecting
81
+
82
+ def get_archive_package_uuids(self, downloader_packages, downloader_links):
83
+ """
84
+ Get set of package UUIDs that contain at least one archive file.
85
+
86
+ Two-phase detection:
87
+ 1. Check extractionStatus in link data (free - catches in-progress/completed extractions)
88
+ 2. Single API call for all remaining packages (catches pre-extraction archives)
89
+
90
+ This correctly handles:
91
+ - Mixed packages (archive + non-archive files)
92
+ - Archives before extraction starts
93
+ - Archives during/after extraction
94
+ """
95
+ if self._archive_package_uuids is not None:
96
+ return self._archive_package_uuids
97
+
98
+ self._archive_package_uuids = set()
99
+
100
+ if not downloader_packages:
101
+ return self._archive_package_uuids
102
+
103
+ all_package_uuids = {p.get("uuid") for p in downloader_packages if p.get("uuid")}
104
+
105
+ # Phase 1: Check extractionStatus in already-fetched link data (free - no API call)
106
+ # This catches packages where extraction is in progress or completed
107
+ for link in downloader_links:
108
+ extraction_status = link.get("extractionStatus")
109
+ if extraction_status: # Any non-empty extraction status means it's an archive
110
+ pkg_uuid = link.get("packageUUID")
111
+ if pkg_uuid:
112
+ self._archive_package_uuids.add(pkg_uuid)
113
+
114
+ # Phase 2: Single API call for all unchecked packages
115
+ unchecked_package_uuids = list(all_package_uuids - self._archive_package_uuids)
116
+
117
+ if unchecked_package_uuids:
118
+ try:
119
+ # One API call for ALL unchecked packages
120
+ archive_infos = self._device.extraction.get_archive_info([], unchecked_package_uuids)
121
+ if archive_infos:
122
+ for archive_info in archive_infos:
123
+ if archive_info:
124
+ # Extract package UUID from response
125
+ pkg_uuid = archive_info.get("packageUUID")
126
+ if pkg_uuid:
127
+ self._archive_package_uuids.add(pkg_uuid)
128
+ except:
129
+ pass
130
+
131
+ return self._archive_package_uuids