quasarr 0.1.6__py3-none-any.whl → 1.23.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.

Files changed (77) hide show
  1. quasarr/__init__.py +316 -42
  2. quasarr/api/__init__.py +187 -0
  3. quasarr/api/arr/__init__.py +387 -0
  4. quasarr/api/captcha/__init__.py +1189 -0
  5. quasarr/api/config/__init__.py +23 -0
  6. quasarr/api/sponsors_helper/__init__.py +166 -0
  7. quasarr/api/statistics/__init__.py +196 -0
  8. quasarr/downloads/__init__.py +319 -256
  9. quasarr/downloads/linkcrypters/__init__.py +0 -0
  10. quasarr/downloads/linkcrypters/al.py +237 -0
  11. quasarr/downloads/linkcrypters/filecrypt.py +444 -0
  12. quasarr/downloads/linkcrypters/hide.py +123 -0
  13. quasarr/downloads/packages/__init__.py +476 -0
  14. quasarr/downloads/sources/al.py +697 -0
  15. quasarr/downloads/sources/by.py +106 -0
  16. quasarr/downloads/sources/dd.py +76 -0
  17. quasarr/downloads/sources/dj.py +7 -0
  18. quasarr/downloads/sources/dl.py +199 -0
  19. quasarr/downloads/sources/dt.py +66 -0
  20. quasarr/downloads/sources/dw.py +14 -7
  21. quasarr/downloads/sources/he.py +112 -0
  22. quasarr/downloads/sources/mb.py +47 -0
  23. quasarr/downloads/sources/nk.py +54 -0
  24. quasarr/downloads/sources/nx.py +42 -83
  25. quasarr/downloads/sources/sf.py +159 -0
  26. quasarr/downloads/sources/sj.py +7 -0
  27. quasarr/downloads/sources/sl.py +90 -0
  28. quasarr/downloads/sources/wd.py +110 -0
  29. quasarr/downloads/sources/wx.py +127 -0
  30. quasarr/providers/cloudflare.py +204 -0
  31. quasarr/providers/html_images.py +22 -0
  32. quasarr/providers/html_templates.py +211 -104
  33. quasarr/providers/imdb_metadata.py +108 -3
  34. quasarr/providers/log.py +19 -0
  35. quasarr/providers/myjd_api.py +201 -40
  36. quasarr/providers/notifications.py +99 -11
  37. quasarr/providers/obfuscated.py +65 -0
  38. quasarr/providers/sessions/__init__.py +0 -0
  39. quasarr/providers/sessions/al.py +286 -0
  40. quasarr/providers/sessions/dd.py +78 -0
  41. quasarr/providers/sessions/dl.py +175 -0
  42. quasarr/providers/sessions/nx.py +76 -0
  43. quasarr/providers/shared_state.py +656 -79
  44. quasarr/providers/statistics.py +154 -0
  45. quasarr/providers/version.py +60 -1
  46. quasarr/providers/web_server.py +1 -1
  47. quasarr/search/__init__.py +144 -15
  48. quasarr/search/sources/al.py +448 -0
  49. quasarr/search/sources/by.py +204 -0
  50. quasarr/search/sources/dd.py +135 -0
  51. quasarr/search/sources/dj.py +213 -0
  52. quasarr/search/sources/dl.py +354 -0
  53. quasarr/search/sources/dt.py +265 -0
  54. quasarr/search/sources/dw.py +94 -67
  55. quasarr/search/sources/fx.py +89 -33
  56. quasarr/search/sources/he.py +196 -0
  57. quasarr/search/sources/mb.py +195 -0
  58. quasarr/search/sources/nk.py +188 -0
  59. quasarr/search/sources/nx.py +75 -21
  60. quasarr/search/sources/sf.py +374 -0
  61. quasarr/search/sources/sj.py +213 -0
  62. quasarr/search/sources/sl.py +246 -0
  63. quasarr/search/sources/wd.py +208 -0
  64. quasarr/search/sources/wx.py +337 -0
  65. quasarr/storage/config.py +39 -10
  66. quasarr/storage/setup.py +269 -97
  67. quasarr/storage/sqlite_database.py +6 -1
  68. quasarr-1.23.0.dist-info/METADATA +306 -0
  69. quasarr-1.23.0.dist-info/RECORD +77 -0
  70. {quasarr-0.1.6.dist-info → quasarr-1.23.0.dist-info}/WHEEL +1 -1
  71. quasarr/arr/__init__.py +0 -423
  72. quasarr/captcha_solver/__init__.py +0 -284
  73. quasarr-0.1.6.dist-info/METADATA +0 -81
  74. quasarr-0.1.6.dist-info/RECORD +0 -31
  75. {quasarr-0.1.6.dist-info → quasarr-1.23.0.dist-info}/entry_points.txt +0 -0
  76. {quasarr-0.1.6.dist-info → quasarr-1.23.0.dist-info/licenses}/LICENSE +0 -0
  77. {quasarr-0.1.6.dist-info → quasarr-1.23.0.dist-info}/top_level.txt +0 -0
quasarr/storage/setup.py CHANGED
@@ -4,15 +4,21 @@
4
4
 
5
5
  import os
6
6
  import sys
7
- from urllib import parse
8
7
 
8
+ import requests
9
9
  from bottle import Bottle, request
10
10
 
11
11
  import quasarr
12
- from quasarr.downloads.sources import nx
13
- from quasarr.storage.config import Config
12
+ import quasarr.providers.html_images as images
13
+ import quasarr.providers.sessions.al
14
+ import quasarr.providers.sessions.dd
15
+ import quasarr.providers.sessions.dl
16
+ import quasarr.providers.sessions.nx
14
17
  from quasarr.providers.html_templates import render_button, render_form, render_success, render_fail
18
+ from quasarr.providers.log import info
19
+ from quasarr.providers.shared_state import extract_valid_hostname
15
20
  from quasarr.providers.web_server import Server
21
+ from quasarr.storage.config import Config
16
22
 
17
23
 
18
24
  def path_config(shared_state):
@@ -24,7 +30,7 @@ def path_config(shared_state):
24
30
  def config_form():
25
31
  config_form_html = f'''
26
32
  <form action="/api/config" method="post">
27
- <label for="config_path">Path</label><br>
33
+ <label for="config_path">Path</label>
28
34
  <input type="text" id="config_path" name="config_path" placeholder="{current_path}"><br>
29
35
  {render_button("Save", "primary", {"type": "submit"})}
30
36
  </form>
@@ -57,129 +63,285 @@ def path_config(shared_state):
57
63
  return render_success(f'Config path set to: "{config_path}"',
58
64
  5)
59
65
 
60
- print(f'Starting web server for config at: "{shared_state.values['internal_address']}".')
61
- print("Please set desired config path there!")
66
+ info(f'Starting web server for config at: "{shared_state.values['internal_address']}".')
67
+ info("Please set desired config path there!")
62
68
  return Server(app, listen='0.0.0.0', port=shared_state.values['port']).serve_temporarily()
63
69
 
64
70
 
71
+ def hostname_form_html(shared_state, message):
72
+ hostname_fields = '''
73
+ <label for="{id}" style="display:inline-flex; align-items:center; gap:4px;">{label}{img_html}</label>
74
+ <input type="text" id="{id}" name="{id}" placeholder="example.com" autocorrect="off" autocomplete="off" value="{value}"><br>
75
+ '''
76
+
77
+ field_html = []
78
+ hostnames = Config('Hostnames') # Load once outside the loop
79
+ for label in shared_state.values["sites"]:
80
+ field_id = label.lower()
81
+ img_html = ''
82
+ try:
83
+ img_data = getattr(images, field_id)
84
+ if img_data:
85
+ img_html = f' <img src="{img_data}" width="16" height="16" style="filter: blur(2px);" alt="{label} icon">'
86
+ except AttributeError:
87
+ pass
88
+
89
+ # Get the current value (if any and non-empty)
90
+ current_value = hostnames.get(field_id)
91
+ if not current_value:
92
+ current_value = '' # Ensure it's empty if None or ""
93
+
94
+ field_html.append(hostname_fields.format(
95
+ id=field_id,
96
+ label=label,
97
+ img_html=img_html,
98
+ value=current_value
99
+ ))
100
+
101
+ hostname_form_content = "".join(field_html)
102
+ button_html = render_button("Save", "primary", {"type": "submit"})
103
+
104
+ template = """
105
+ <div id="message" style="margin-bottom:0.5em;">{message}</div>
106
+ <div id="error-msg" style="color:red; margin-bottom:1em;"></div>
107
+
108
+ <form action="/api/hostnames" method="post" onsubmit="return validateHostnames(this)">
109
+ {hostname_form_content}
110
+ {button}
111
+ </form>
112
+
113
+ <script>
114
+ function validateHostnames(form) {{
115
+ var errorDiv = document.getElementById('error-msg');
116
+ errorDiv.textContent = '';
117
+
118
+ var inputs = form.querySelectorAll('input[type="text"]');
119
+ for (var i = 0; i < inputs.length; i++) {{
120
+ if (inputs[i].value.trim() !== '') {{
121
+ return true;
122
+ }}
123
+ }}
124
+
125
+ errorDiv.textContent = 'Please fill in at least one hostname!';
126
+ inputs[0].focus();
127
+ return false;
128
+ }}
129
+ </script>
130
+ """
131
+ return template.format(
132
+ message=message,
133
+ hostname_form_content=hostname_form_content,
134
+ button=button_html
135
+ )
136
+
137
+
138
+ def save_hostnames(shared_state, timeout=5, first_run=True):
139
+ hostnames = Config('Hostnames')
140
+
141
+ # Collect submitted hostnames, validate, and track errors
142
+ valid_domains = {}
143
+ errors = {}
144
+
145
+ for site_key in shared_state.values['sites']:
146
+ shorthand = site_key.lower()
147
+ raw_value = request.forms.get(shorthand)
148
+ # treat missing or empty string as intentional clear, no validation
149
+ if raw_value is None or raw_value.strip() == '':
150
+ continue
151
+
152
+ # non-empty submission: must validate
153
+ result = extract_valid_hostname(raw_value, shorthand)
154
+ domain = result.get('domain')
155
+ message = result.get('message', 'Error checking the hostname you provided!')
156
+ if domain:
157
+ valid_domains[site_key] = domain
158
+ else:
159
+ errors[site_key] = message
160
+
161
+ # Filter out any accidental empty domains and require at least one valid hostname overall
162
+ valid_domains = {k: d for k, d in valid_domains.items() if d}
163
+ if not valid_domains:
164
+ # report last or generic message
165
+ fail_msg = next(iter(errors.values()), 'No valid hostname provided!')
166
+ return render_fail(fail_msg)
167
+
168
+ # Save: valid ones, explicit empty for those omitted cleanly, leave untouched if error
169
+ changed_sites = []
170
+ for site_key in shared_state.values['sites']:
171
+ shorthand = site_key.lower()
172
+ raw_value = request.forms.get(shorthand)
173
+ # determine if change applies
174
+ if site_key in valid_domains:
175
+ new_val = valid_domains[site_key]
176
+ old_val = hostnames.get(shorthand) or ''
177
+ if old_val != new_val:
178
+ hostnames.save(shorthand, new_val)
179
+ changed_sites.append(shorthand)
180
+ elif raw_value is None:
181
+ # no submission: leave untouched
182
+ continue
183
+ elif raw_value.strip() == '':
184
+ old_val = hostnames.get(shorthand) or ''
185
+ if old_val != '':
186
+ hostnames.save(shorthand, '')
187
+
188
+ quasarr.providers.web_server.temp_server_success = True
189
+
190
+ # Build success message, include any per-site errors
191
+ success_msg = 'At least one valid hostname set!'
192
+ if errors:
193
+ optional_text = "<br>".join(f"{site}: {msg}" for site, msg in errors.items()) + "<br>"
194
+ else:
195
+ optional_text = "All provided hostnames are valid.<br>"
196
+
197
+ if not first_run:
198
+ # Append restart notice for specific sites that actually changed
199
+ for site in changed_sites:
200
+ if site.lower() in {'al', 'dd', 'dl', 'nx'}:
201
+ optional_text += f"{site.upper()}: You must restart Quasarr and follow additional steps to start using this site.<br>"
202
+
203
+ return render_success(success_msg, timeout, optional_text=optional_text)
204
+
205
+
65
206
  def hostnames_config(shared_state):
66
207
  app = Bottle()
67
208
 
68
209
  @app.get('/')
69
210
  def hostname_form():
70
- hostname_fields = '''
71
- <label for="{id}">{label}</label><br>
72
- <input type="text" id="{id}" name="{id}" placeholder="example.com" autocorrect="off" autocomplete="off"><br>
73
- '''
74
-
75
- hostname_form_content = "".join(
76
- [hostname_fields.format(id=label.lower(), label=label) for label in shared_state.values["sites"]])
77
-
78
- hostname_form_html = f'''
79
- <form action="/api/hostnames" method="post">
80
- {hostname_form_content}
81
- {render_button("Save", "primary", {"type": "submit"})}
82
- </form>
83
- '''
84
-
85
- return render_form("Set at least one valid hostname", hostname_form_html)
211
+ message = """<p>
212
+ If you're having trouble setting this up, take a closer look at
213
+ <a href="https://github.com/rix1337/Quasarr?tab=readme-ov-file#instructions" target="_blank" rel="noopener noreferrer">
214
+ step one of these instructions.
215
+ </a>
216
+ </p>"""
217
+ return render_form("Set at least one valid hostname", hostname_form_html(shared_state, message))
86
218
 
87
219
  @app.post("/api/hostnames")
88
220
  def set_hostnames():
89
- def extract_domain(url, shorthand):
90
- # Check if both characters from the shorthand appear in the url
91
- try:
92
- if '://' not in url:
93
- url = 'http://' + url
94
- result = parse.urlparse(url)
95
- domain = result.netloc
96
-
97
- # Check if both characters in the shorthand are in the domain
98
- if all(char in domain for char in shorthand):
99
- print(f"{domain} matches both characters from {shorthand}. Continuing...")
100
- return domain
101
- else:
102
- print(f"Invalid domain {domain}: Does not contain both characters from shorthand {shorthand}")
103
- return None
104
- except Exception as e:
105
- print(f"Error parsing URL {url}: {e}")
106
- return None
107
-
108
- hostnames = Config('Hostnames')
109
-
110
- hostname_set = False
111
-
112
- for key in shared_state.values["sites"]:
113
- shorthand = key.lower()
114
- hostname = request.forms.get(shorthand)
115
- try:
116
- if hostname:
117
- hostname = extract_domain(hostname, shorthand)
118
- except Exception as e:
119
- print(f"Error extracting domain from {hostname}: {e}")
120
- continue
121
-
122
- if hostname:
123
- hostnames.save(key, hostname)
124
- hostname_set = True
125
-
126
- if hostname_set:
127
- quasarr.providers.web_server.temp_server_success = True
128
- return render_success("At least one valid hostname set",
129
- 5)
130
- else:
131
- return render_fail("No valid hostname provided!")
221
+ return save_hostnames(shared_state)
132
222
 
133
- print(
134
- f'Hostnames not set. Starting web server for config at: "{shared_state.values['internal_address']}".')
135
- print("Please set at least one valid hostname there!")
223
+ info(f'Hostnames not set. Starting web server for config at: "{shared_state.values['internal_address']}".')
224
+ info("Please set at least one valid hostname there!")
136
225
  return Server(app, listen='0.0.0.0', port=shared_state.values['port']).serve_temporarily()
137
226
 
138
227
 
139
- def nx_credentials_config(shared_state):
228
+ def hostname_credentials_config(shared_state, shorthand, domain):
140
229
  app = Bottle()
141
230
 
231
+ shorthand = shorthand.upper()
232
+
142
233
  @app.get('/')
143
- def nx_credentials_form():
144
- form_content = '''
145
- <label for="user">Username</label><br>
146
- <input type="text" id="user" name="user" placeholder="user" autocorrect="off"><br>
234
+ def credentials_form():
235
+ form_content = f'''
236
+ <span>If required register account at: <a href="https://{domain}">{domain}</a>!</span><br><br>
237
+ <label for="user">Username</label>
238
+ <input type="text" id="user" name="user" placeholder="User" autocorrect="off"><br>
147
239
 
148
- <label for="password">Password</label><br>
240
+ <label for="password">Password</label>
149
241
  <input type="password" id="password" name="password" placeholder="Password"><br>
150
242
  '''
151
243
 
152
244
  form_html = f'''
153
- <form action="/api/nx_credentials" method="post">
245
+ <form action="/api/credentials/{shorthand}" method="post">
154
246
  {form_content}
155
247
  {render_button("Save", "primary", {"type": "submit"})}
156
248
  </form>
157
249
  '''
158
250
 
159
- return render_form("Set User and Password for NX", form_html)
251
+ return render_form(f"Set User and Password for {shorthand}", form_html)
160
252
 
161
- @app.post("/api/nx_credentials")
162
- def set_nx_credentials():
253
+ @app.post("/api/credentials/<sh>")
254
+ def set_credentials(sh):
163
255
  user = request.forms.get('user')
164
256
  password = request.forms.get('password')
165
- nx_config = Config("NX")
257
+ config = Config(shorthand)
166
258
 
167
259
  if user and password:
168
- nx_config.save("user", user)
169
- nx_config.save("password", password)
170
-
171
- if nx.create_and_persist_session(shared_state):
172
- quasarr.providers.web_server.temp_server_success = True
173
- return render_success("NX credentials set successfully", 5)
260
+ config.save("user", user)
261
+ config.save("password", password)
262
+
263
+ if sh.lower() == "al":
264
+ if quasarr.providers.sessions.al.create_and_persist_session(shared_state):
265
+ quasarr.providers.web_server.temp_server_success = True
266
+ return render_success(f"{sh} credentials set successfully", 5)
267
+ elif sh.lower() == "dd":
268
+ if quasarr.providers.sessions.dd.create_and_persist_session(shared_state):
269
+ quasarr.providers.web_server.temp_server_success = True
270
+ return render_success(f"{sh} credentials set successfully", 5)
271
+ elif sh.lower() == "dl":
272
+ if quasarr.providers.sessions.dl.create_and_persist_session(shared_state):
273
+ quasarr.providers.web_server.temp_server_success = True
274
+ return render_success(f"{sh} credentials set successfully", 5)
275
+ elif sh.lower() == "nx":
276
+ if quasarr.providers.sessions.nx.create_and_persist_session(shared_state):
277
+ quasarr.providers.web_server.temp_server_success = True
278
+ return render_success(f"{sh} credentials set successfully", 5)
279
+ else:
280
+ quasarr.providers.web_server.temp_server_success = False
281
+ return render_fail(f"Unknown site shorthand! ({sh})")
174
282
 
175
- nx_config.save("user", "")
176
- nx_config.save("password", "")
283
+ config.save("user", "")
284
+ config.save("password", "")
177
285
  return render_fail("User and Password wrong or empty!")
178
286
 
179
- print(
180
- f'NX credentials required to decrypt download links. '
287
+ info(
288
+ f'"{shorthand.lower()}" credentials required to access download links. '
181
289
  f'Starting web server for config at: "{shared_state.values['internal_address']}".')
182
- print("Please set your NX user and password there! First register an account if you don't have one yet.")
290
+ info(f"If needed register here: 'https://{domain}'")
291
+ info("Please set your credentials now, to allow Quasarr to launch!")
292
+ return Server(app, listen='0.0.0.0', port=shared_state.values['port']).serve_temporarily()
293
+
294
+
295
+ def flaresolverr_config(shared_state):
296
+ app = Bottle()
297
+
298
+ @app.get('/')
299
+ def url_form():
300
+ form_content = '''
301
+ <span><a href="https://github.com/FlareSolverr/FlareSolverr?tab=readme-ov-file#installation">A local instance</a>
302
+ must be running and reachable to Quasarr!</span><br><br>
303
+ <label for="url">FlareSolverr URL</label>
304
+ <input type="text" id="url" name="url" placeholder="http://192.168.0.1:8191/v1"><br>
305
+ '''
306
+ form_html = f'''
307
+ <form action="/api/flaresolverr" method="post">
308
+ {form_content}
309
+ {render_button("Save", "primary", {"type": "submit"})}
310
+ </form>
311
+ '''
312
+ return render_form("Set FlareSolverr URL", form_html)
313
+
314
+ @app.post('/api/flaresolverr')
315
+ def set_flaresolverr_url():
316
+ url = request.forms.get('url').strip()
317
+ config = Config("FlareSolverr")
318
+
319
+ if url:
320
+ try:
321
+ headers = {"Content-Type": "application/json"}
322
+ data = {
323
+ "cmd": "request.get",
324
+ "url": "http://www.google.com/",
325
+ "maxTimeout": 30000
326
+ }
327
+ response = requests.post(url, headers=headers, json=data, timeout=30)
328
+ if response.status_code == 200:
329
+ config.save("url", url)
330
+ print(f'Using Flaresolverr URL: "{url}"')
331
+ quasarr.providers.web_server.temp_server_success = True
332
+ return render_success("FlareSolverr URL saved successfully!", 5)
333
+ except requests.RequestException:
334
+ pass
335
+
336
+ # on failure, clear any existing value and notify user
337
+ config.save("url", "")
338
+ return render_fail("Could not reach FlareSolverr at that URL (expected HTTP 200).")
339
+
340
+ info(
341
+ '"flaresolverr" URL is required for proper operation. '
342
+ f'Starting web server for config at: "{shared_state.values["internal_address"]}".'
343
+ )
344
+ info("Please enter your FlareSolverr URL now.")
183
345
  return Server(app, listen='0.0.0.0', port=shared_state.values['port']).serve_temporarily()
184
346
 
185
347
 
@@ -187,24 +349,33 @@ def jdownloader_config(shared_state):
187
349
  app = Bottle()
188
350
 
189
351
  @app.get('/')
190
- def hostname_form():
352
+ def jd_form():
191
353
  verify_form_html = f'''
354
+ <span>If required register account at: <a href="https://my.jdownloader.org/login.html#register">
355
+ my.jdownloader.org</a>!</span><br>
356
+
357
+ <p><strong>JDownloader must be running and connected to My JDownloader!</strong></p><br>
358
+
192
359
  <form id="verifyForm" action="/api/verify_jdownloader" method="post">
193
- <label for="user">E-Mail</label><br>
360
+ <label for="user">E-Mail</label>
194
361
  <input type="text" id="user" name="user" placeholder="user@example.org" autocorrect="off"><br>
195
- <label for="pass">Password</label><br>
362
+ <label for="pass">Password</label>
196
363
  <input type="password" id="pass" name="pass" placeholder="Password"><br>
197
364
  {render_button("Verify Credentials",
198
365
  "secondary",
199
366
  {"id": "verifyButton", "type": "button", "onclick": "verifyCredentials()"})}
200
367
  </form>
368
+
369
+ <p>Some JDownloader settings will be enforced by Quasarr on startup.</p>
370
+
201
371
  <form action="/api/store_jdownloader" method="post" id="deviceForm" style="display: none;">
202
372
  <input type="hidden" id="hiddenUser" name="user">
203
373
  <input type="hidden" id="hiddenPass" name="pass">
204
- <label for="device">JDownloader</label><br>
374
+ <label for="device">JDownloader</label>
205
375
  <select id="device" name="device"></select><br>
206
376
  {render_button("Save", "primary", {"type": "submit"})}
207
377
  </form>
378
+ <p><strong>Saving may take a while!</strong></p><br>
208
379
  '''
209
380
 
210
381
  verify_script = '''
@@ -243,7 +414,7 @@ def jdownloader_config(shared_state):
243
414
  }
244
415
  </script>
245
416
  '''
246
- return render_form("Set your credentials from my.jdownloader.org", verify_form_html, verify_script)
417
+ return render_form("Set your credentials for My JDownloader", verify_form_html, verify_script)
247
418
 
248
419
  @app.post("/api/verify_jdownloader")
249
420
  def verify_jdownloader():
@@ -287,8 +458,9 @@ def jdownloader_config(shared_state):
287
458
 
288
459
  return render_fail("Could not set credentials!")
289
460
 
290
- print(
461
+ info(
291
462
  f'My-JDownloader-Credentials not set. '
292
463
  f'Starting web server for config at: "{shared_state.values['internal_address']}".')
293
- print("Please set your Credentials there!")
464
+ info("If needed register here: 'https://my.jdownloader.org/login.html#register'")
465
+ info("Please set your credentials now, to allow Quasarr to launch!")
294
466
  return Server(app, listen='0.0.0.0', port=shared_state.values['port']).serve_temporarily()
@@ -6,6 +6,7 @@ import sqlite3
6
6
  import time
7
7
 
8
8
  from quasarr.providers import shared_state
9
+ from quasarr.providers.log import info
9
10
 
10
11
 
11
12
  class DataBase(object):
@@ -27,7 +28,7 @@ class DataBase(object):
27
28
  self._conn.execute(f"CREATE TABLE {self._table} (key, value)")
28
29
  self._conn.commit()
29
30
  except sqlite3.OperationalError as e:
30
- print(f"Error accessing Quasarr.db: {e}")
31
+ info(f"Error accessing Quasarr.db: {e}")
31
32
 
32
33
  def retrieve(self, key):
33
34
  query = f"SELECT value FROM {self._table} WHERE key=?"
@@ -54,6 +55,7 @@ class DataBase(object):
54
55
  # using this parameterized query to prevent SQL injection, which requires a tuple as second argument
55
56
  self._conn.execute(query, (key, value))
56
57
  self._conn.commit()
58
+ return True
57
59
 
58
60
  def update_store(self, key, value):
59
61
  delete_query = f"DELETE FROM {self._table} WHERE key=?"
@@ -63,13 +65,16 @@ class DataBase(object):
63
65
  # using this parameterized query to prevent SQL injection, which requires a tuple as second argument
64
66
  self._conn.execute(insert_query, (key, value))
65
67
  self._conn.commit()
68
+ return True
66
69
 
67
70
  def delete(self, key):
68
71
  query = f"DELETE FROM {self._table} WHERE key=?"
69
72
  # using this parameterized query to prevent SQL injection, which requires a tuple as second argument
70
73
  self._conn.execute(query, (key,))
71
74
  self._conn.commit()
75
+ return True
72
76
 
73
77
  def reset(self):
74
78
  self._conn.execute(f"DROP TABLE IF EXISTS {self._table}")
75
79
  self._conn.commit()
80
+ return True