diff --git a/CB/Core.py b/CB/Core.py
index ed9ecda..7ec1b98 100644
--- a/CB/Core.py
+++ b/CB/Core.py
@@ -1,12 +1,15 @@
import os
import sys
import json
+import html
import shutil
import zipfile
import datetime
+import requests
+from bs4 import BeautifulSoup
from tqdm import tqdm
from checksumdir import dirhash
-from . import __version__
+from . import retry, __version__
from .ElvUI import ElvUIAddon
from .CurseForge import CurseForgeAddon
from .WoWInterface import WoWInterfaceAddon
@@ -194,6 +197,15 @@ def find_orphans(self):
orphaneconfig.append(os.path.join(root, f)[4:])
return orphanedaddon, orphaneconfig
+ @retry(custom_error='Failed to execute the search.')
+ def search(self, query):
+ results = []
+ soup = BeautifulSoup(requests.get(f'https://www.curseforge.com/wow/addons/search?search='
+ f'{html.escape(query.strip())}').content, 'html.parser')
+ for row in soup.find_all('h2', attrs={'class': 'list-item__title strong mg-b-05'}):
+ results.append(f'https://www.curseforge.com{row.parent["href"]}')
+ return results
+
def create_reg(self):
with open('CurseBreaker.reg', 'w') as outfile:
outfile.write('Windows Registry Editor Version 5.00\n[HKEY_CURRENT_USER\Software\Classes\curse]\n"URL Proto'
diff --git a/CB/CurseForge.py b/CB/CurseForge.py
index fc0c891..e1ba44d 100644
--- a/CB/CurseForge.py
+++ b/CB/CurseForge.py
@@ -7,7 +7,7 @@
class CurseForgeAddon:
- @retry
+ @retry()
def __init__(self, url):
if url.startswith('https://www.curseforge.com/wow/addons/'):
soup = BeautifulSoup(requests.get(url).content, 'html.parser')
@@ -33,7 +33,7 @@ def version_search(self, tag):
break
return version
- @retry
+ @retry()
def get_current_version(self):
self.currentVersion = self.version_search('Release')
if self.currentVersion is None:
@@ -50,7 +50,7 @@ def get_current_version(self):
if self.currentVersion is None:
raise RuntimeError
- @retry
+ @retry()
def get_addon(self):
self.archive = zipfile.ZipFile(io.BytesIO(requests.get(self.downloadUrl).content))
for file in self.archive.namelist():
diff --git a/CB/ElvUI.py b/CB/ElvUI.py
index 963a51e..7cb75da 100644
--- a/CB/ElvUI.py
+++ b/CB/ElvUI.py
@@ -8,7 +8,7 @@
class ElvUIAddon:
- @retry
+ @retry()
def __init__(self, branch):
self.soup = BeautifulSoup(requests.get(f'https://git.tukui.org/elvui/elvui/tree/{branch}').content,
'html.parser')
@@ -25,7 +25,7 @@ def get_current_version(self):
except Exception:
raise RuntimeError('Failed to parse addon page. URL is wrong or your source has some issues.')
- @retry
+ @retry()
def get_addon(self):
self.archive = zipfile.ZipFile(io.BytesIO(requests.get(self.downloadUrl).content))
for file in self.archive.namelist():
diff --git a/CB/TukUI.py b/CB/TukUI.py
index 849f554..0aa37e7 100644
--- a/CB/TukUI.py
+++ b/CB/TukUI.py
@@ -8,7 +8,7 @@
class TukUIAddon:
- @retry
+ @retry()
def __init__(self):
self.soup = BeautifulSoup(requests.get('https://git.tukui.org/Tukz/Tukui/tree/master').content, 'html.parser')
self.name = 'TukUI'
@@ -23,7 +23,7 @@ def get_current_version(self):
except Exception:
raise RuntimeError('Failed to parse addon page. URL is wrong or your source has some issues.')
- @retry
+ @retry()
def get_addon(self):
self.archive = zipfile.ZipFile(io.BytesIO(requests.get(self.downloadUrl).content))
for file in self.archive.namelist():
diff --git a/CB/WoWInterface.py b/CB/WoWInterface.py
index 597e747..d9b0028 100644
--- a/CB/WoWInterface.py
+++ b/CB/WoWInterface.py
@@ -7,7 +7,7 @@
class WoWInterfaceAddon:
- @retry
+ @retry()
def __init__(self, url):
self.soup = BeautifulSoup(requests.get(url).content, 'html.parser')
self.name = self.soup.find('meta', attrs={'property': 'og:title'})['content']
@@ -22,7 +22,7 @@ def get_current_version(self):
except Exception:
raise RuntimeError('Failed to parse addon page. URL is wrong or your source has some issues.')
- @retry
+ @retry()
def get_addon(self):
dsoup = BeautifulSoup(requests.get(self.downloadUrl).content, 'html.parser')
self.archive = zipfile.ZipFile(io.BytesIO(requests.get(dsoup.find('div', attrs={'class': 'manuallink'}).
diff --git a/CB/__init__.py b/CB/__init__.py
index fb34f46..c88d165 100644
--- a/CB/__init__.py
+++ b/CB/__init__.py
@@ -4,18 +4,24 @@
__docformat__ = 'restructuredtext en'
-def retry(func):
- def inner(*args, **kwargs):
- for i in range(3):
- # noinspection PyBroadException
- try:
- result = func(*args, **kwargs)
- except KeyboardInterrupt:
- raise
- except Exception:
- continue
+def retry(custom_error=False):
+ def wraps(func):
+ def inner(*args, **kwargs):
+ for i in range(3):
+ # noinspection PyBroadException
+ try:
+ result = func(*args, **kwargs)
+ except KeyboardInterrupt:
+ raise
+ except Exception:
+ continue
+ else:
+ return result
else:
- return result
- else:
- raise RuntimeError('Failed to parse addon page. URL is wrong or your source has some issues.')
- return inner
+ if custom_error:
+ raise RuntimeError(custom_error)
+ else:
+ raise RuntimeError('Failed to parse addon page. URL is wrong or your source has some issues.')
+ return inner
+ return wraps
+
diff --git a/CurseBreaker.py b/CurseBreaker.py
index e8b8541..19c0e5d 100644
--- a/CurseBreaker.py
+++ b/CurseBreaker.py
@@ -143,7 +143,7 @@ def print_header(self):
f'{__version__} ~~~\n'))
def setup_completer(self):
- commands = ['install', 'uninstall', 'update', 'force_update', 'status', 'orphans', 'toggle_backup',
+ commands = ['install', 'uninstall', 'update', 'force_update', 'status', 'orphans', 'search', 'toggle_backup',
'uri_integration', 'help', 'exit']
addons = sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower())
for addon in addons:
@@ -254,6 +254,15 @@ def c_toggle_backup(self, _):
printft('Backup of WTF directory is now:',
HTML('ENABLED') if status else HTML('DISABLED'))
+ def c_search(self, args):
+ if args:
+ results = self.core.search(args)
+ printft(HTML('Top results of your search:'))
+ for url in results:
+ printft(url)
+ else:
+ printft(HTML('Usage:\n\tThis command accepts a search query as an argument.'))
+
def c_help(self, _):
printft(HTML('install [URL]\n\tCommand accepts a comma-separated list of links.'))
printft(HTML('uninstall [URL/Name]\n\tCommand accepts a comma-separated list of links or'
@@ -265,6 +274,7 @@ def c_help(self, _):
'ate.'))
printft(HTML('status\n\tPrints the current state of all installed addons.'))
printft(HTML('orphans\n\tPrints list of orphaned directories and files.'))
+ printft(HTML('search [Keyword]\n\tExecute addon search on CurseForge.'))
printft(HTML('toggle_backup\n\tEnable/disable automatic daily backup of WTF directory.'))
printft(HTML('uri_integration\n\tEnable integration with CurseForge page. "Install" butt'
'on will now start this application.'))