Skip to content

Commit 1155f57

Browse files
committed
version 3.0.7
- fix update && update download object
1 parent 00e2926 commit 1155f57

3 files changed

Lines changed: 153 additions & 23 deletions

File tree

oclp_r/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def __init__(self) -> None:
2020
self.metallib_api_link: str = ""
2121

2222
# Patcher Versioning
23-
self.patcher_version: str = "3.0.6" # OCLP-R
23+
self.patcher_version: str = "3.0.7" # OCLP-R
2424
self.patcher_support_pkg_version: str = "1.11.1" # PatcherSupportPkg
2525
self.copyright_date: str = "Copyright © 2020-2026 Dortania and Hackdoc"
2626
self.patcher_name: str = "OCLP-R"

oclp_r/support/network_handler.py

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import hashlib
1414
import atexit
1515
import json
16+
import math
1617
from typing import Union
1718
from pathlib import Path
1819

@@ -188,6 +189,11 @@ def __init__(self, url: str, path: str, size:str=None, resume_download: bool = T
188189
self.downloaded_file_size: float = 0.0
189190
self.downloaded_file_offset: float = 0.0
190191
self.start_time: float = time.time()
192+
self.multipart_threshold: float = 1024 * 1024 * 50
193+
self.chunk_count: int = 16
194+
self.part_paths: list[Path] = []
195+
self.part_errors: list[str] = []
196+
self._download_lock = threading.Lock()
191197

192198
self.error: bool = False
193199
self.should_stop: bool = False
@@ -403,6 +409,115 @@ def _clear_progress(self) -> None:
403409
except Exception as e:
404410
logging.warning(self.trans["Failed to clear progress file: {0}"].format(str(e)))
405411

412+
def _supports_range_download(self) -> bool:
413+
try:
414+
result = SESSION.head(self.url, allow_redirects=True, timeout=5)
415+
if result.headers.get("Accept-Ranges", "").lower() == "bytes":
416+
return True
417+
418+
probe = NetworkUtilities().get(self.url, stream=True, timeout=10, headers={"Range": "bytes=0-0"})
419+
return probe.status_code == 206
420+
except Exception:
421+
return False
422+
423+
def _should_use_multipart_download(self) -> bool:
424+
if self.resume_download and self.downloaded_file_offset > 0:
425+
return False
426+
if self.total_file_size == 0.0:
427+
return False
428+
if self.total_file_size < self.multipart_threshold:
429+
return False
430+
if self.chunk_count <= 1:
431+
return False
432+
return self._supports_range_download()
433+
434+
def _build_download_ranges(self) -> list[tuple[int, int]]:
435+
part_size = max(1, math.ceil(self.total_file_size / self.chunk_count))
436+
ranges = []
437+
start = 0
438+
439+
while start < self.total_file_size:
440+
end = min(start + part_size - 1, int(self.total_file_size) - 1)
441+
ranges.append((start, end))
442+
start = end + 1
443+
444+
return ranges
445+
446+
def _download_part(self, part_index: int, start: int, end: int) -> None:
447+
part_path = Path(f"{self.filepath}.part{part_index}")
448+
self.part_paths[part_index] = part_path
449+
headers = {"Range": f"bytes={start}-{end}"}
450+
logging.info(f"- Download part {part_index + 1}/{len(self.part_paths)}: bytes={start}-{end}")
451+
response = NetworkUtilities().get(self.url, stream=True, timeout=100, headers=headers)
452+
453+
if response.status_code != 206:
454+
raise Exception(f"Unexpected status code for part {part_index}: {response.status_code}")
455+
456+
with open(part_path, "wb") as file:
457+
for chunk in response.iter_content(1024 * 1024 * 4):
458+
if self.should_stop:
459+
raise Exception(self.trans["Download stopped"])
460+
if chunk:
461+
file.write(chunk)
462+
with self._download_lock:
463+
self.downloaded_file_size += len(chunk)
464+
465+
logging.info(f"- Completed part {part_index + 1}/{len(self.part_paths)}: {part_path}")
466+
467+
def _merge_download_parts(self) -> None:
468+
with open(self.filepath, "wb") as destination:
469+
for part_path in self.part_paths:
470+
with open(part_path, "rb") as source:
471+
while True:
472+
chunk = source.read(1024 * 1024 * 4)
473+
if not chunk:
474+
break
475+
destination.write(chunk)
476+
if self.should_checksum:
477+
self._update_checksum(chunk)
478+
479+
for part_path in self.part_paths:
480+
if part_path and part_path.exists():
481+
part_path.unlink()
482+
483+
def _download_multipart(self) -> None:
484+
ranges = self._build_download_ranges()
485+
self.part_paths = [None] * len(ranges)
486+
self.part_errors = []
487+
threads = []
488+
489+
logging.info(f"- Using multipart download with {len(ranges)} parts")
490+
491+
def _worker(index: int, start: int, end: int) -> None:
492+
try:
493+
self._download_part(index, start, end)
494+
except Exception as error:
495+
self.part_errors.append(str(error))
496+
self.should_stop = True
497+
498+
for index, (start, end) in enumerate(ranges):
499+
thread = threading.Thread(target=_worker, args=(index, start, end), name=f"DownloadPart-{index}")
500+
thread.start()
501+
threads.append(thread)
502+
503+
for thread in threads:
504+
thread.join()
505+
506+
if self.part_errors:
507+
logging.error(f"- Multipart download failed with {len(self.part_errors)} part error(s)")
508+
self.delete_temp_files()
509+
raise Exception(self.part_errors[0])
510+
511+
self._merge_download_parts()
512+
self.download_complete = True
513+
self._clear_progress()
514+
logging.info(self.trans["Download complete: {0}"].format(self.filename))
515+
logging.info(self.trans["Stats:"])
516+
logging.info(self.trans["- Downloaded size: {0}"].format(utilities.human_fmt(self.downloaded_file_size)))
517+
logging.info(self.trans["- Time elapsed: {0:.2f} seconds"].format((time.time() - self.start_time)))
518+
logging.info(self.trans["- Speed: {0}/s"].format(utilities.human_fmt(self.downloaded_file_size / (time.time() - self.start_time))))
519+
logging.info(self.trans["- Location: {0}"].format(self.filepath))
520+
406521

407522
def _download(self, display_progress: bool = False) -> None:
408523
"""
@@ -423,13 +538,17 @@ def _download(self, display_progress: bool = False) -> None:
423538
if self._prepare_working_directory(self.filepath) is False:
424539
raise Exception(self.error_msg)
425540

541+
if self._should_use_multipart_download():
542+
self._download_multipart()
543+
return
544+
426545
headers = {}
427546
if self.resume_download and self.downloaded_file_offset > 0:
428547
headers['Range'] = f'bytes={self.downloaded_file_offset}-'
429548
logging.info(self.trans["Resuming download from byte {0}"].format(self.downloaded_file_offset))
430549

431550
response = NetworkUtilities().get(self.url, stream=True, timeout=100, headers=headers)
432-
551+
logging.info(f"- Download URL: {self.url}")
433552
mode = 'ab' if self.resume_download and self.downloaded_file_offset > 0 else 'wb'
434553
with open(self.filepath, mode) as file:
435554
atexit.register(self.stop)
@@ -467,9 +586,10 @@ def _download(self, display_progress: bool = False) -> None:
467586
self.error_msg = str(e)
468587
self.status = DownloadStatus.ERROR
469588
logging.error(self.trans["Error downloading {0}: {1}"].format(self.url, self.error_msg))
470-
471-
self.status = DownloadStatus.COMPLETE
472-
utilities.enable_sleep_after_running()
589+
else:
590+
self.status = DownloadStatus.COMPLETE
591+
finally:
592+
utilities.enable_sleep_after_running()
473593

474594

475595
def get_percent(self) -> float:
@@ -548,8 +668,13 @@ def delete_temp_files(self) -> None:
548668
if self.progress_file.exists():
549669
self.progress_file.unlink()
550670
logging.info(self.trans["Deleted progress file: {0}"].format(self.progress_file))
671+
672+
for part_path in self.part_paths:
673+
if part_path and part_path.exists():
674+
part_path.unlink()
675+
logging.info(self.trans["Deleted partially downloaded file: {0}"].format(part_path))
551676
except Exception as e:
552-
logging.warning(self.trans["Failed to delete temporary files: {0}"].format(str(e)))
677+
logging.warning(self.trans["Failed to delete temporary files: {0}"].format(str(e)))
553678

554679
def stop(self) -> None:
555680
"""

oclp_r/support/updates.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ def __init__(self, global_constants: constants.Constants) -> None:
3131

3232
self.latest_details = None
3333

34+
def _apply_github_proxy(self, url: str) -> str:
35+
if self.constants.github_proxy_link == "Default":
36+
return url
37+
elif self.constants.github_proxy_link == "SimpleHac":
38+
return f"https://gitapi.simplehac.top/{url}"
39+
elif self.constants.github_proxy_link == "ghfast":
40+
return f"https://ghfast.top/{url}"
41+
elif self.constants.github_proxy_link == "gh-proxy":
42+
return f"https://gh-proxy.com/{url}"
43+
elif self.constants.github_proxy_link == "ghllkk":
44+
return f"https://gh.llkk.cc/{url}"
45+
46+
return url
47+
3448
def check_if_newer(self, version: Union[str, version.Version]) -> bool:
3549
"""
3650
Check if the provided version is newer than the local version
@@ -91,11 +105,11 @@ def check_binary_updates(self) -> Optional[dict]:
91105
if self.constants.special_build is True:
92106
# Special builds do not get updates through the updater
93107
return None
94-
95-
if self.constants.commit_info[0] == "Running from source":
96-
# Running from source, skip update check
108+
109+
if self.constants.commit_info[0] in ["Running from source", "Built from source"] or self.constants.commit_info[2] is None or self.constants.commit_info[2] == "":
110+
# skip when you're running from socure
97111
return None
98-
112+
99113
if self.latest_details:
100114
# We already checked
101115
return self.latest_details
@@ -122,22 +136,13 @@ def check_binary_updates(self) -> Optional[dict]:
122136
for asset in data_set["assets"]:
123137
logging.info(self.trans["Found asset: {0}"].format(asset['name']))
124138
if asset["name"] == "OCLP-R.pkg":
125-
begi=f"https://github.com/hackdoc/OCLP-R/releases/{latest_remote_version}"
126-
if self.constants.github_proxy_link=="Default":
127-
link=begi
128-
129-
elif self.constants.github_proxy_link=="ghfast":
130-
link="https://ghfast.top/"+begi
131-
elif self.constants.github_proxy_link=="gh-proxy":
132-
link="https://gh-proxy.com/"+begi
133-
elif self.constants.github_proxy_link=="ghllkk":
134-
link="https://gh.llkk.cc/"+begi
139+
release_link = f"https://github.com/hackdoc/OCLP-R/releases/{latest_remote_version}"
135140
self.latest_details = {
136141
"Name": asset["name"],
137142
"Version": latest_remote_version,
138-
"Link": asset["browser_download_url"],
139-
"Github Link": link,
143+
"Link": self._apply_github_proxy(asset["browser_download_url"]),
144+
"Github Link": self._apply_github_proxy(release_link),
140145
}
141146
return self.latest_details
142147

143-
return None
148+
return None

0 commit comments

Comments
 (0)