diff --git a/README.md b/README.md
index b741cd7..bceb9a0 100644
--- a/README.md
+++ b/README.md
@@ -46,15 +46,6 @@ We help you download at the fastest possible speed without having to wait for ea
-
-
-
-
-
- Supports multiple simultaneous downloads and can be increased or decreased depending on the environment.
-
-
-
## 😼 Introduction to key features
@@ -66,8 +57,6 @@ We help you download at the fastest possible speed without having to wait for ea
⭐ In addition to the `1ficher` link, when you directly enter a shortened `URL` such as `ouo.io`, an automatic link that bypasses `reCAPTCHA` is added.
-⭐ Supports simultaneous proxy downloads using `Threading` (basic 3 experimental)
-
⭐ The default download folder path is the Windows ‘Download’ folder.
_Your life is short. Don't wait any longer._
@@ -115,6 +104,7 @@ _Your life is short. Don't wait any longer._
- Added exception handling when adding duplicate downloads with the same file name (processing required after actual 1fichier URL parsing)
- Supports asynchronous download using `Asyncio` instead of `Threading`, which is slow when downloading simultaneously (increases speed)
- In addition to the basic specification ‘1ficher’, it is necessary to check whether programs from other similar download sites are supported.
+- Supports simultaneous proxy downloads using `Threading`
diff --git a/build command.txt b/build command.txt
new file mode 100644
index 0000000..aa83a89
--- /dev/null
+++ b/build command.txt
@@ -0,0 +1 @@
+pyinstaller --windowed --noconsole --onefile --noconfirm --clean --hiddenimport=_cffi_backend --additional-hooks-dir=. --icon=core/gui/res/ico.ico --add-data "core/gui/res/*.*;res/" .\1fichier-dl.py
\ No newline at end of file
diff --git a/core/download/helpers.py b/core/download/helpers.py
index 1a4030a..a97c004 100644
--- a/core/download/helpers.py
+++ b/core/download/helpers.py
@@ -126,7 +126,7 @@ def get_link_info(url: str) -> list:
return [name, size]
except:
logging.debug(__name__+' Exception')
- return None
+ return ['Error', '- MB']
def is_valid_link(url: str) -> bool:
diff --git a/core/download/workers.py b/core/download/workers.py
index 6835d5f..69ec87a 100644
--- a/core/download/workers.py
+++ b/core/download/workers.py
@@ -36,90 +36,115 @@ def __init__(self, actions, cached_download='', password=''):
@pyqtSlot()
def run(self):
self.valid_links = []
-
- if isinstance(self.links, str):
- self.valid_links = [self.links]
- else:
- links = self.links.toPlainText().splitlines()
- for link in links:
- logging.debug('valid_links:'+str(link.strip()))
- # If the shortened URL is ouo bypass, recaptcha bypass
- if 'ouo.io' in link:
- link = ouo_bypass(url=link)['bypassed_link']
- logging.debug('bypassed link: ' + str(link))
-
- link = link.strip()
- if is_valid_link(link):
- if not 'https://' in link[0:8] and not 'http://' in link[0:7]:
- link = f'https://{link}'
- if '&' in link:
- link = link.split('&')[0]
- self.valid_links.append(link)
-
- if not self.valid_links:
- self.signals.alert_signal.emit(
- 'The link(s) you inserted were not valid.')
+ self.invalid_links = []
+
+ try:
+ if self.links.toPlainText():
+ links = self.links.toPlainText().splitlines()
+ for link in links:
+ link = link.strip()
+ logging.debug('Processing link: ' + str(link))
+ # If the shortened URL is ouo bypass, recaptcha bypass
+ try:
+ if 'ouo.io' in link:
+ bypassed = ouo_bypass(url=link)
+ link = bypassed['bypassed_link']
+ logging.debug('Bypassed link: ' + str(link))
+ except Exception as e:
+ logging.error(f"Failed to bypass ouo.io link {link}: {e}")
+ self.invalid_links.append(link)
+ continue
+
+ # Link validation
+ try:
+ if is_valid_link(link):
+ if not (link.startswith('https://') or link.startswith('http://')):
+ link = f'https://{link}'
+ link = link.split('&')[0]
+ self.valid_links.append(link)
+ else:
+ raise ValueError(f'Invalid link format: {link}')
+ except ValueError as ve:
+ logging.warning(ve)
+ self.invalid_links.append(link)
+ self.signals.alert_signal.emit(f'Invalid link format: {link}')
+ continue # Continue to next link
+
+ if len(self.invalid_links) > 0 :
self.gui.hide_loading_overlay()
# Reset link input window
self.gui.add_btn.setEnabled(True)
self.gui.links.setEnabled(True)
self.gui.password.setEnabled(True)
-
- for link in self.valid_links:
- if '/dir/' in link:
- folder = requests.get(f'{link}?json=1')
- folder = folder.json()
- for f in folder:
- link = f['link']
- info = [f['filename'], convert_size(int(f['size']))]
- info.extend(['Added', None, '0 B/s', ''])
- row = []
-
- for val in info:
- data = QStandardItem(val)
- data.setFlags(data.flags() & ~Qt.ItemIsEditable)
- row.append(data)
-
- if f['password'] == 1:
- password = QStandardItem(self.password)
- row.append(password)
- self.gui.hide_loading_overlay()
- else:
- no_password = QStandardItem('No password')
- no_password.setFlags(data.flags() & ~Qt.ItemIsEditable)
- row.append(no_password)
-
- self.signals.download_signal.emit(
- row, link, True, self.dl_name, self.progress)
- if self.cached_download:
- self.cached_downloads.remove(self.cached_download)
- else:
- info = get_link_info(link)
- if info is not None:
- is_private = True if info[0] == 'Private File' else False
- info[0] = self.dl_name if self.dl_name else info[0]
- info.extend(['Added', None, '0 B/s', ''])
- row = []
-
- for val in info:
- data = QStandardItem(val)
- data.setFlags(data.flags() & ~Qt.ItemIsEditable)
- row.append(data)
-
- if is_private:
- password = QStandardItem(self.password)
- row.append(password)
- self.gui.hide_loading_overlay()
- else:
- no_password = QStandardItem('No password')
- no_password.setFlags(data.flags() & ~Qt.ItemIsEditable)
- row.append(no_password)
-
- self.signals.download_signal.emit(
- row, link, True, self.dl_name, self.progress)
- if self.cached_download:
- self.cached_downloads.remove(self.cached_download)
-
+ # 링크 추가 문구 원복
+ self.gui.add_links_complete()
+ else :
+ for link in self.valid_links:
+ try:
+ if '/dir/' in link:
+ folder = requests.get(f'{link}?json=1')
+ folder = folder.json()
+ for f in folder:
+ link = f['link']
+ info = [f['filename'], convert_size(int(f['size']))]
+ info.extend(['Waiting', None, '0 B/s', ''])
+ row = []
+
+ for val in info:
+ data = QStandardItem(val)
+ data.setFlags(data.flags() & ~Qt.ItemIsEditable)
+ row.append(data)
+
+ if f['password'] == 1:
+ password = QStandardItem(self.password)
+ row.append(password)
+ self.gui.hide_loading_overlay()
+ else:
+ no_password = QStandardItem('No password')
+ no_password.setFlags(data.flags() & ~Qt.ItemIsEditable)
+ row.append(no_password)
+
+ self.signals.download_signal.emit(
+ row, link, True, self.dl_name, self.progress)
+ if self.cached_download:
+ self.cached_downloads.remove(self.cached_download)
+ else:
+ info = get_link_info(link)
+ if info is not None:
+ # parsing Avoid errors
+ if info[0] == 'Error':
+ self.signals.alert_signal.emit(f'We couldn\'t get the actual information for the file to download.\n{link}')
+ self.gui.hide_loading_overlay()
+ else:
+ is_private = True if info[0] == 'Private File' else False
+ info[0] = self.dl_name if self.dl_name else info[0]
+ info.extend(['Waiting', None, '0 B/s', ''])
+ row = []
+
+ for val in info:
+ data = QStandardItem(val)
+ data.setFlags(data.flags() & ~Qt.ItemIsEditable)
+ row.append(data)
+
+ if is_private:
+ password = QStandardItem(self.password)
+ row.append(password)
+ self.gui.hide_loading_overlay()
+ else:
+ no_password = QStandardItem('No password')
+ no_password.setFlags(data.flags() & ~Qt.ItemIsEditable)
+ row.append(no_password)
+
+ self.signals.download_signal.emit(
+ row, link, True, self.dl_name, self.progress)
+ if self.cached_download:
+ self.cached_downloads.remove(self.cached_download)
+ except Exception as e:
+ logging.error(f"Error processing link {link}: {e}")
+ continue
+
+ except Exception as e:
+ logging.error(f"Unexpected error in run method: {e}")
class DownloadWorker(QRunnable):
def __init__(self, link, table_model, data, settings, dl_name=''):
diff --git a/core/gui/gui.py b/core/gui/gui.py
index 0f81b66..d6f480d 100644
--- a/core/gui/gui.py
+++ b/core/gui/gui.py
@@ -99,7 +99,7 @@ def __init__(self, gui):
self.filter_thread = QThreadPool()
self.download_thread = QThreadPool()
# Limits concurrent downloads to 1.
- self.download_thread.setMaxThreadCount(3)
+ self.download_thread.setMaxThreadCount(1)
self.download_workers = []
self.gui = gui
self.handle_init()
@@ -283,19 +283,47 @@ def change_theme(self, theme=None):
qdarktheme.setup_theme("dark")
# self.gui.app.setPalette(dark_theme)
+ def get_language(self):
+ language = os.getenv('LANGUAGE') or 'en' # Get language from environment variable
+ return language
+
+ def set_language(self, language=None):
+ if language:
+ self.gui.theme_select.setCurrentIndex(language)
+
+ if(self.gui.theme_select.currentIndex()) :
+ return 'kr'
+ else :
+ return 'en'
+
+ def load_messages(self, language):
+ messages = {}
+ messages_file = f'messages_{language}.txt'
+
+ with open(messages_file, 'r', encoding='utf-8') as f:
+ for line in f:
+ key, value = line.strip().split(',')
+ messages[key] = value
+
+ return messages
+
def save_settings(self):
with open(abs_config('app/settings'), 'wb') as f:
settings = []
- settings.append(self.gui.dl_directory_input.text())
# Download Directory - 0
+ settings.append(self.gui.dl_directory_input.text())
# Theme - 1
settings.append(self.gui.theme_select.currentIndex())
- settings.append(self.gui.timeout_input.value())
# Timeout - 2
+ settings.append(self.gui.timeout_input.value())
# Proxy Settings - 3
settings.append(self.gui.proxy_settings_input.text())
- # Number of multi downloads
- settings.append(self.gui.thread_input.value())
+ # Thread Settings - 4
+ settings.append(1)
+ # settings.append(self.gui.thread_input.value())
+ # Select language
+ # Lang Settings - 5
+ # settings.append(self.gui.lang_select.currentIndex())
pickle.dump(settings, f)
self.settings = settings
self.gui.settings.hide()
@@ -549,6 +577,15 @@ def settings_win(self):
vbox.setAlignment(Qt.AlignTop)
form_layout = QFormLayout()
+ # Change Lang
+ # form_layout.addRow(QLabel('Language:'))
+
+ # self.lang_select = QComboBox()
+ # self.lang_select.addItems(['Korean', 'English'])
+ # self.lang_select.currentIndexChanged.connect(
+ # self.actions.set_language)
+ # form_layout.addRow(self.lang_select)
+
# Change Directory
form_layout.addRow(QLabel('Download directory:'))
@@ -594,14 +631,14 @@ def settings_win(self):
form_layout_c = QFormLayout()
# Timeout
- form_layout_c.addRow(QLabel('Timeout (Default 30s):'))
- self.timeout_input = QSpinBox()
- if self.actions.settings is not None:
- self.timeout_input.setValue(self.actions.settings[2])
- else:
- self.timeout_input.setValue(30)
+ # form_layout_c.addRow(QLabel('Timeout (Default 30s):'))
+ # self.timeout_input = QSpinBox()
+ # if self.actions.settings is not None:
+ # self.timeout_input.setValue(self.actions.settings[2])
+ # else:
+ # self.timeout_input.setValue(30)
- form_layout_c.addRow(self.timeout_input)
+ # form_layout_c.addRow(self.timeout_input)
# Proxy settings
form_layout_c.addRow(QLabel('Enter proxy list directly:'))
@@ -668,17 +705,24 @@ def add_links_complete(self):
self.links.clear()
def add_to_download_list(self):
- # Disable the 'Add to download list' button.
- self.add_btn.setText("Adding to download list...")
- self.add_btn.setEnabled(False)
-
# It takes the entered link and converts it into a list.
links_text = self.links.toPlainText()
- download_links = links_text.split('\n')
- self.links.setDisabled(True)
- self.password.setDisabled(True)
-
- for link in download_links:
- if link.strip(): # Append only if the line is not blank.
- # Use 'add_links' to add download links.
- self.actions.add_links(link)
+
+ if(links_text) :
+ add_links_texts = []
+ # Disable the 'Add to download list' button.
+ self.add_btn.setText("Adding to download list...")
+ self.add_btn.setEnabled(False)
+
+ download_links = links_text.split('\n')
+ self.links.setDisabled(True)
+ self.password.setDisabled(True)
+
+ for link in download_links:
+ if link.strip(): # Append only if the line is not blank.
+ add_links_texts.append(link)
+
+ # Use 'add_links' to add download links.
+ self.actions.add_links('\n'.join(add_links_texts))
+ else:
+ alert('Please enter a list of download links.')
diff --git a/https_proxy_list.txt b/https_proxy_list.txt
index 7b74c3f..ccf8796 100644
--- a/https_proxy_list.txt
+++ b/https_proxy_list.txt
@@ -1,4 +1,5 @@
+https://raw.githubusercontent.com/r00tee/Proxy-List/main/Https.txt
+https://raw.githubusercontent.com/r00tee/Proxy-List/main/Socks5.txt
https://raw.githubusercontent.com/Zaeem20/FREE_PROXIES_LIST/master/https.txt
-https://raw.githubusercontent.com/roosterkid/openproxylist/main/HTTPS_RAW.txt
-https://raw.githubusercontent.com/ErcinDedeoglu/proxies/main/proxies/https.txt
-https://raw.githubusercontent.com/casals-ar/proxy.casals.ar/main/https
+https://raw.githubusercontent.com/SevenworksDev/proxy-list/main/proxies/https.txt
+https://raw.githubusercontent.com/ErcinDedeoglu/proxies/main/proxies/https.txt
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 8e3f47e..2ba1341 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,9 @@
-PyQt5==5.15.9
+PyQt5
lxml==4.9.3
curl_cffi==0.5.7
urllib3==2.0.4
requests
beautifulsoup4
pyqtdarktheme
+pyinstaller==5.13.2
#pyinstaller==5.13.0 # python -m pip uninstall pyinstalle, python ./waf all --target-arch=64bit
\ No newline at end of file