Unit3Dup 0.8.7__py3-none-any.whl → 0.8.9__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.
common/command.py CHANGED
@@ -47,6 +47,7 @@ class CommandLine:
47
47
  parser.add_argument("-ftp", "--ftp", action="store_true", help="Connect to FTP")
48
48
 
49
49
  # optional
50
+ parser.add_argument("-dump", "--dump", type=str, help="Download all torrent files")
50
51
  parser.add_argument("-s", "--search", type=str, help="Search for torrent")
51
52
  parser.add_argument("-i", "--info", type=str, help="Get info on torrent")
52
53
  parser.add_argument("-up", "--uploader", type=str, help="Search by uploader")
common/database.py ADDED
@@ -0,0 +1,94 @@
1
+ import json
2
+ import sqlite3
3
+
4
+ # Torrent attributes
5
+ create_table_sql = ('\n'
6
+ 'CREATE TABLE IF NOT EXISTS torrents (\n'
7
+ ' id INTEGER PRIMARY KEY AUTOINCREMENT,\n'
8
+ ' name TEXT,\n'
9
+ ' category TEXT,\n'
10
+ ' category_id INTEGER,\n'
11
+ ' created_at TEXT,\n'
12
+ ' description TEXT,\n'
13
+ ' details_link TEXT,\n'
14
+ ' download_link TEXT,\n'
15
+ ' double_upload BOOLEAN,\n'
16
+ ' featured BOOLEAN,\n'
17
+ ' freeleech TEXT,\n'
18
+ ' igdb_id INTEGER,\n'
19
+ ' imdb_id TEXT,\n'
20
+ ' info_hash TEXT,\n'
21
+ ' internal BOOLEAN,\n'
22
+ ' leechers INTEGER,\n'
23
+ ' magnet_link TEXT,\n'
24
+ ' mal_id INTEGER,\n'
25
+ ' media_info TEXT,\n'
26
+ ' release_year INTEGER,\n'
27
+ ' resolution TEXT,\n'
28
+ ' resolution_id INTEGER,\n'
29
+ ' seeders INTEGER,\n'
30
+ ' size INTEGER,\n'
31
+ ' times_completed INTEGER,\n'
32
+ ' tmdb_id INTEGER,\n'
33
+ ' tvdb_id INTEGER,\n'
34
+ ' type TEXT,\n'
35
+ ' type_id INTEGER,\n'
36
+ ' uploader TEXT,\n'
37
+ ' personal_release BOOLEAN,\n'
38
+ ' refundable BOOLEAN,\n'
39
+ ' num_file INTEGER,\n'
40
+ ' bd_info TEXT,\n'
41
+ ' genres TEXT,\n'
42
+ ' poster TEXT,\n'
43
+ ' meta TEXT,\n'
44
+ ' files TEXT\n'
45
+ ')\n')
46
+
47
+
48
+ class Database:
49
+ """
50
+ Create a new database and populate it with torrents attributes
51
+ Search torrents based on attributes
52
+ """
53
+
54
+ def __init__(self, db_file):
55
+ self.filename = db_file
56
+ self.database = sqlite3.connect(f"{db_file}.db")
57
+ self.cursor = self.database.cursor()
58
+ self.build()
59
+
60
+ def build(self):
61
+ self.cursor.execute(create_table_sql)
62
+ self.database.commit()
63
+
64
+ def write(self, data: dict):
65
+ for key, value in data.items():
66
+ if isinstance(value, (dict,list)):
67
+ data[key] = json.dumps(value)
68
+
69
+ keys = ', '.join(data.keys())
70
+ placeholders = ', '.join(['?'] * len(data))
71
+ values = tuple(data.values())
72
+
73
+ sql = f'''INSERT INTO torrents ({keys}) VALUES ({placeholders})'''
74
+ self.cursor.execute(sql, values)
75
+ self.database.commit()
76
+
77
+ def search(self, query: str):
78
+ # Search a substring in 'name'
79
+ self.cursor.execute("SELECT name FROM torrents WHERE name LIKE ?", ('%' + query + '%',))
80
+ results = self.cursor.fetchall()
81
+ # print the results
82
+ for r in results:
83
+ print(f"[database]{r}")
84
+ input("[DATABASE] Press Enter to continue...")
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
@@ -1,6 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import os.path
3
3
 
4
+ import httpx
5
+
4
6
  from common.external_services.Pw.core.models.torrent_client_config import (
5
7
  TorrentClientConfig,
6
8
  )
@@ -37,7 +39,7 @@ class PwAPI(MyHttp):
37
39
  custom_console.bot_question_log("No PW_API_KEY provided\n")
38
40
  exit(1)
39
41
 
40
- def get_indexers(self) -> ["Indexer"]:
42
+ def get_indexers(self) -> list[type[[Indexer]]]:
41
43
  """Get all indexers."""
42
44
 
43
45
  response = self.get_url(url=f"{self.base_url}/indexer", params={})
@@ -46,15 +48,10 @@ class PwAPI(MyHttp):
46
48
  indexers_list = response.json()
47
49
  return [Indexer(**indexer) for indexer in indexers_list]
48
50
  else:
49
- return []
51
+ return [Indexer]
50
52
 
51
- def get_torrent_url(self, url: str, filename: str):
52
-
53
- response = self.get_url(url=url)
54
- if response.status_code == 200:
55
- # Write the torrent to file
56
- with open(os.path.join(config_settings.options.PW_TORRENT_ARCHIVE_PATH,f"{filename}.torrent"), 'wb') as f:
57
- f.write(response.content)
53
+ def get_torrent_url(self, url: str, filename: str)-> httpx.Response :
54
+ return self.get_url(url=url)
58
55
 
59
56
  def search(self, query: str) -> list[Search] | None:
60
57
  """Get search queue."""
@@ -5,7 +5,10 @@ import os
5
5
 
6
6
  from common.external_services.Pw.pw_service import PwService
7
7
  from common.utility import ManageTitles
8
+ from common.database import Database
8
9
  from common import config_settings
10
+ from unit3dup.media import Media
11
+
9
12
 
10
13
  from qbittorrent import Client
11
14
  from view import custom_console
@@ -19,28 +22,42 @@ class PwManager:
19
22
  # filename for the new download
20
23
  self.filename = ManageTitles.normalize_filename(self.search)
21
24
 
25
+ # Select the tracker database
26
+ self.database = Database(db_file=cli.tracker)
27
+
22
28
 
23
29
  def process(self):
24
30
 
25
- # a new qbittorent instance
26
- qb = Client(f"http://{config_settings.tracker_config.QBIT_HOST}:{config_settings.tracker_config.QBIT_PORT}/")
31
+ # a new qbittorrent instance
32
+ qb = Client(f"http://{config_settings.torrent_client_config.QBIT_HOST}:{config_settings.torrent_client_config.QBIT_PORT}/")
27
33
  # a new pw instance
28
34
  pw_service = PwService()
29
35
  # Query the indexers
30
36
  search = pw_service.search(query=self.search)
31
37
 
38
+ content = []
32
39
  if search:
33
40
  for index, s in enumerate(search):
34
- if s.seeders > 0:
35
- torrent_file = search[index]
36
- custom_console.log(torrent_file.downloadUrl)
37
- pw_service.get_torrent_from_pw(torrent_url=torrent_file.downloadUrl,download_filename=self.filename)
38
-
39
- qb.login(username=config_settings.tracker_config.QBIT_USER,
40
- password=config_settings.tracker_config.QBIT_PASS)
41
-
42
- qb.download_from_file(
43
- file_buffer=open(os.path.join(config_settings.options.PW_TORRENT_ARCHIVE_PATH,
44
- f"{self.filename}.torrent"), "rb"),
45
- savepath=config_settings.options.PW_DOWNLOAD_PATH,
46
- )
41
+ if s.seeders > 0:
42
+ category = s.categories[0]['name']
43
+ if category in ['Movies','TV','TV/HD']:
44
+ content.append(s)
45
+ custom_console.bot_process_table_pw(content=content)
46
+
47
+
48
+ for c in content:
49
+ test = Media(folder=f"c:\\test\\{c.fileName}", subfolder=f"c:\\test\\{c.fileName}")
50
+ print(f"[Prowlarr] {c.fileName}")
51
+ self.database.search(test.guess_title)
52
+
53
+
54
+ """"
55
+ qb.login(username=config_settings.torrent_client_config.QBIT_USER,
56
+ password=config_settings.torrent_client_config.QBIT_PASS)
57
+
58
+ for torrent in content:
59
+ filename = str(os.path.join(config_settings.options.PW_TORRENT_ARCHIVE_PATH,torrent.fileName))
60
+ print(filename)
61
+ magnet = pw_service.get_torrent_from_pw(torrent_url=torrent.downloadUrl,download_filename=filename)
62
+ qb.download_from_link(magnet, savepath=config_settings.options.PW_DOWNLOAD_PATH)
63
+ """
@@ -23,7 +23,12 @@ class PwService:
23
23
  def send_torrent_to_client(self, payload):
24
24
  return self.pw_api.send_torrent_to_client(payload)
25
25
 
26
- def get_torrent_from_pw(self, torrent_url: str, download_filename: str):
27
- return self.pw_api.get_torrent_url(url=torrent_url, filename=download_filename)
26
+ def get_torrent_from_pw(self, torrent_url: str, download_filename: str)-> str | None:
27
+ response = self.pw_api.get_torrent_url(url=torrent_url, filename=download_filename)
28
+ # Redirect (PW)
29
+ if response.status_code == 301:
30
+ return response.headers.get('Location')
31
+ return None
32
+
28
33
 
29
34
 
@@ -5,7 +5,6 @@ import json
5
5
  import time
6
6
  import requests
7
7
 
8
- from PIL import Image
9
8
  from abc import ABC, abstractmethod
10
9
  from common import config_settings
11
10
  from view import custom_console
@@ -16,6 +15,7 @@ class ImageUploader(ABC):
16
15
  self.image = base64.b64encode(image)
17
16
  self.key = key
18
17
  self.image_name = image_name
18
+ self.timeout = 30
19
19
 
20
20
  @abstractmethod
21
21
  def get_endpoint(self):
@@ -40,7 +40,7 @@ class ImageUploader(ABC):
40
40
  try:
41
41
  upload_n += 1
42
42
  response = requests.post(
43
- self.get_endpoint(), data = data, files = files, timeout = 20
43
+ self.get_endpoint(), data = data, files = files, timeout = self.timeout
44
44
  )
45
45
  response.raise_for_status()
46
46
  return response.json()
@@ -61,7 +61,7 @@ class ImageUploader(ABC):
61
61
  except requests.exceptions.Timeout:
62
62
  custom_console.bot_log(
63
63
  f"[{self.__class__.__name__}] We did not receive a response from the server"
64
- f" within the 20 second limit"
64
+ f" within the {self.timeout} second limit"
65
65
  )
66
66
  break
67
67
 
@@ -163,6 +163,20 @@ class ImgFi(ImageUploader):
163
163
  def get_field_name(self) -> str:
164
164
  return 'source'
165
165
 
166
+ class PassIMA(ImageUploader):
167
+
168
+ priority= config_settings.user_preferences.PASSIMA_PRIORITY
169
+ def get_endpoint(self) -> str:
170
+ return "https://passtheima.ge/api/1/upload"
171
+
172
+ def get_data(self) -> dict:
173
+ return {
174
+ "key": self.key,
175
+ "title": self.image_name,
176
+ }
177
+
178
+ def get_field_name(self) -> str:
179
+ return 'source'
166
180
 
167
181
 
168
182
  class ImageUploaderFallback:
@@ -213,6 +227,10 @@ class ImageUploaderFallback:
213
227
 
214
228
  if uploader_host == "ImgFi":
215
229
  return response['image']['url']
230
+
231
+ if uploader_host == "PassIMA":
232
+ return response['image']['url']
233
+
216
234
  return None
217
235
 
218
236
  class Build:
@@ -232,6 +250,7 @@ class Build:
232
250
  self.LENSDUMP_KEY= config_settings.tracker_config.LENSDUMP_KEY
233
251
  self.PTSCREENS_KEY= config_settings.tracker_config.PTSCREENS_KEY
234
252
  self.IMGFI_KEY = config_settings.tracker_config.IMGFI_KEY
253
+ self.PASSIMA_KEY = config_settings.tracker_config.PASSIMA_KEY
235
254
  self.extracted_frames = extracted_frames
236
255
 
237
256
 
@@ -251,6 +270,7 @@ class Build:
251
270
  PtScreens(img_bytes, self.PTSCREENS_KEY,image_name=image_name),
252
271
  LensDump(img_bytes, self.LENSDUMP_KEY,image_name=image_name),
253
272
  ImgFi(img_bytes, self.IMGFI_KEY,image_name=image_name),
273
+ PassIMA(img_bytes, self.PASSIMA_KEY, image_name=image_name),
254
274
  ]
255
275
 
256
276
  # Sorting list based on priority
common/settings.py CHANGED
@@ -13,7 +13,7 @@ from common.utility import ManageTitles
13
13
  from common import trackers
14
14
 
15
15
  config_file = "Unit3Dbot.json"
16
- version = "0.8.7"
16
+ version = "0.8.9"
17
17
 
18
18
  if os.name == "nt":
19
19
  PW_TORRENT_ARCHIVE_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "pw_torrent_archive"
@@ -40,12 +40,20 @@ def get_default_path(field: str)-> str:
40
40
  "CACHE_PATH": CACHE_PATH,
41
41
  "WATCHER_DESTINATION_PATH": WATCHER_DESTINATION_PATH,
42
42
  "WATCHER_PATH": WATCHER_PATH,
43
- "PW_DOWNLOAD": PW_DOWNLOAD_PATH,
43
+ "PW_DOWNLOAD_PATH": PW_DOWNLOAD_PATH,
44
44
  "PW_TORRENT_ARCHIVE_PATH": PW_TORRENT_ARCHIVE_PATH
45
45
  }
46
46
  return str(default_paths[field])
47
47
 
48
48
 
49
+
50
+ class Ccolors:
51
+ OKCYAN = '\033[96m'
52
+ OKGREEN = '\033[92m'
53
+ WARNING = '\033[93m'
54
+ FAIL = '\033[91m'
55
+ ENDC = '\033[0m'
56
+
49
57
  class TrackerConfig(BaseModel):
50
58
  ITT_URL: str
51
59
  ITT_APIKEY: str | None = None
@@ -60,6 +68,7 @@ class TrackerConfig(BaseModel):
60
68
  LENSDUMP_KEY: str | None = None
61
69
  PTSCREENS_KEY: str | None = None
62
70
  IMGFI_KEY: str | None = None
71
+ PASSIMA_KEY: str | None = None
63
72
  YOUTUBE_KEY: str | None = None
64
73
  IGDB_CLIENT_ID: str | None = None
65
74
  IGDB_ID_SECRET: str | None = None
@@ -92,6 +101,7 @@ class UserPreferences(BaseModel):
92
101
  FREE_IMAGE_PRIORITY: int = 2
93
102
  IMGBB_PRIORITY: int = 3
94
103
  IMGFI_PRIORITY: int = 4
104
+ PASSIMA_PRIORITY: int = 5
95
105
  NUMBER_OF_SCREENSHOTS: int = 4
96
106
  YOUTUBE_FAV_CHANNEL_ID: str | None = None
97
107
  YOUTUBE_CHANNEL_ENABLE: bool = False
@@ -120,7 +130,7 @@ class Options(BaseModel):
120
130
  PW_API_KEY: str | None = None
121
131
  PW_URL: str = "http://localhost:9696/api/v1"
122
132
  PW_TORRENT_ARCHIVE_PATH: str | None = None
123
- PW_DOWNLOAD: str | None = None
133
+ PW_DOWNLOAD_PATH: str | None = None
124
134
  FTPX_USER: str = "user"
125
135
  FTPX_PASS: str = "pass"
126
136
  FTPX_IP: str = "127.0.0.1"
@@ -415,11 +425,11 @@ class Config(BaseModel):
415
425
  'CACHE_SCR','CACHE_DBONLINE', 'PERSONAL_RELEASE']:
416
426
  section[field] = Validate.boolean(value=section[field], field_name=field)
417
427
 
418
- if field in ['TORRENT_COMMENT','PW_TORRENT_ARCHIVE_PATH','WATCHER_PATH','DEFAULT_TRACKER']:
428
+ if field in ['TORRENT_COMMENT','WATCHER_PATH','DEFAULT_TRACKER']:
419
429
  section[field] = Validate.string(value=section[field], field_name=field)
420
430
 
421
431
  if field in ['NUMBER_OF_SCREENSHOTS','COMPRESS_SCSHOT','IMGBB_PRIORITY','FREE_IMAGE_PRIORITY',
422
- 'LENSDUMP_PRIORITY','WATCHER_INTERVAL','SIZE_TH', 'FAST_LOAD']:
432
+ 'LENSDUMP_PRIORITY','PASSIMA_PRIORITY','WATCHER_INTERVAL','SIZE_TH', 'FAST_LOAD']:
423
433
  section[field] = Validate.integer(value=section[field], field_name=field)
424
434
 
425
435
  if field == 'PREFERRED_LANG':
@@ -441,11 +451,29 @@ class Config(BaseModel):
441
451
  section[field] =Validate.unit3dup_path(path=section[field],field_name=field,
442
452
  default_path=get_default_path(field=field))
443
453
 
454
+
444
455
  return v
445
456
 
446
457
  @model_validator(mode='before')
447
458
  def set_default_options(cls, v):
448
- return v or Options()
459
+ section = v['options']
460
+
461
+ for field, value in section.items():
462
+ if value is None:
463
+ print(f"Please fix the '{field}' value")
464
+ exit(1)
465
+ else:
466
+ field = field.upper()
467
+
468
+ if field == 'PW_TORRENT_ARCHIVE_PATH':
469
+ section[field] = Validate.unit3dup_path(path=section[field], field_name=field,
470
+ default_path=get_default_path(field=field))
471
+
472
+ if field == 'PW_DOWNLOAD_PATH':
473
+ section[field] = Validate.unit3dup_path(path=section[field], field_name=field,
474
+ default_path=get_default_path(field=field))
475
+
476
+ return v
449
477
 
450
478
  @model_validator(mode='before')
451
479
  def set_default_console_options(cls, v):
@@ -502,6 +530,7 @@ class Load:
502
530
  "LENSDUMP_KEY": "no_key",
503
531
  "PTSCREENS_KEY": "no_key",
504
532
  "IMGFI_KEY": "no_key",
533
+ "PASSIMA_KEY": "no_key",
505
534
  "YOUTUBE_KEY": "no_key",
506
535
  "IGDB_CLIENT_ID": "no_key",
507
536
  "IGDB_ID_SECRET": "no_key",
@@ -532,6 +561,7 @@ class Load:
532
561
  "FREE_IMAGE_PRIORITY": 2,
533
562
  "IMGBB_PRIORITY": 3,
534
563
  "IMGFI_PRIORITY": 4,
564
+ "PASSIMA_PRIORITY": 5,
535
565
  "NUMBER_OF_SCREENSHOTS": 4,
536
566
  "YOUTUBE_FAV_CHANNEL_ID": "UCGCbxpnt25hWPFLSbvwfg_w",
537
567
  "YOUTUBE_CHANNEL_ENABLE": "False",
@@ -558,7 +588,7 @@ class Load:
558
588
  "PW_API_KEY": "no_key",
559
589
  "PW_URL": "http://localhost:9696/api/v1",
560
590
  "PW_TORRENT_ARCHIVE_PATH": ".",
561
- "PW_DOWNLOAD": ".",
591
+ "PW_DOWNLOAD_PATH": ".",
562
592
  "FTPX_USER": "user",
563
593
  "FTPX_PASS": "pass",
564
594
  "FTPX_IP": "127.0.0.1",
@@ -741,10 +771,11 @@ class JsonConfig:
741
771
  return json.loads(json_data)
742
772
 
743
773
  except json.JSONDecodeError as e:
744
- print(f"Config Loading error.. {e}")
745
- print(r"Try to Check '\\ characters. Example: ")
746
- print(r"C:\myfolder -> not correct ")
747
- print(r"C:/myfolder -> CORRECT ")
774
+ print(f"* Please fix the error{Ccolors.WARNING} near Line {e.lineno}{Ccolors.ENDC}"
775
+ f" and {Ccolors.WARNING}Column {e.colno}{Ccolors.ENDC} in the config file: *\n")
776
+ print(f"{e.msg}\n")
777
+ # Seek And...
778
+ self.aim(line=e.lineno,col=e.colno)
748
779
  exit(1)
749
780
  except FileNotFoundError:
750
781
  print(f"Configuration '{self.default_json_path}' not found")
@@ -797,3 +828,34 @@ class JsonConfig:
797
828
 
798
829
  print(message)
799
830
 
831
+ def aim(self, line: int, col: int):
832
+ """
833
+ Try to identify the exact location of json error
834
+ Args:
835
+ line: Error line from the try block
836
+ col: Error line from the try block
837
+ Returns:
838
+ None
839
+ """
840
+
841
+ # Open the configuration file
842
+ with open(self.default_json_path, 'r') as file:
843
+ lines = file.readlines()
844
+
845
+ # Test the line value
846
+ if line <= len(lines):
847
+ # Create a "context" around the error....
848
+ line_context1 = lines[line -2].rstrip('\n')
849
+ line_context2 = lines[line + 1].rstrip('\n')
850
+
851
+ # Try to identify the position
852
+ line_text = lines[line - 1].rstrip('\n')
853
+ print(f"{line_context1}")
854
+ print(f"{Ccolors.WARNING}>>> {line_text}{Ccolors.ENDC}")
855
+
856
+ # Put the cursor under the error
857
+ cursor = ' ' * (col-1) + '^'
858
+ print(f"{Ccolors.WARNING} {cursor}{Ccolors.ENDC}")
859
+ print(f"{line_context2}")
860
+ else:
861
+ print("Line number is out of range !")
unit3dup/__main__.py CHANGED
@@ -127,8 +127,10 @@ def main():
127
127
 
128
128
  # Pw
129
129
  if cli.args.pw:
130
- bot = Bot(path=cli.args.pw,cli=cli.args, trackers_name_list=tracker_name_list)
131
- bot.pw()
130
+ print("Not yet implemented")
131
+ # bot = Bot(path=cli.args.pw,cli=cli.args, trackers_name_list=tracker_name_list)
132
+ # bot.pw()
133
+ return
132
134
 
133
135
 
134
136
  # ftp and upload
@@ -154,6 +156,12 @@ def main():
154
156
  torrent_info.view_search(cli.args.search)
155
157
  return
156
158
 
159
+ # Dump
160
+ if cli.args.dump:
161
+ print("Not yet implemented")
162
+ # torrent_info.view_search(cli.args.dump,inkey=False)
163
+ return
164
+
157
165
  if cli.args.info:
158
166
  torrent_info.view_search(cli.args.info, info=True)
159
167
  return
unit3dup/torrent.py CHANGED
@@ -1,8 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import re
3
+ import time
3
4
  import requests
4
5
 
5
6
  from common.trackers.trackers import TRACKData
7
+ from common.database import Database
6
8
  from unit3dup import pvtTracker
7
9
  from view import custom_console
8
10
 
@@ -10,8 +12,9 @@ class Torrent:
10
12
 
11
13
  def __init__(self, tracker_name: str):
12
14
 
13
- self.perPage = 130
15
+ self.perPage = 100
14
16
  self.tracker = pvtTracker.Unit3d(tracker_name=tracker_name)
17
+ self.database = Database(db_file=tracker_name)
15
18
 
16
19
  def get_unique_id(self, media_info: str) -> str:
17
20
  # Divido per campi
@@ -142,7 +145,6 @@ class View(Torrent):
142
145
  def __init__(self, tracker_name: str):
143
146
  super().__init__(tracker_name=tracker_name)
144
147
 
145
- self.perPage = 130
146
148
  # Load the constant tracker
147
149
  self.tracker_data = TRACKData.load_from_module(tracker_name=tracker_name)
148
150
  print()
@@ -171,10 +173,8 @@ class View(Torrent):
171
173
  f" -> {item['attributes']['name']}"
172
174
  )
173
175
 
174
- @staticmethod
175
- def print_normal(tracker_data: dict):
176
+ def print_normal(self, tracker_data: dict):
176
177
  data = [item for item in tracker_data["data"]]
177
-
178
178
  for item in data:
179
179
  if item['attributes']['tmdb_id'] != 0:
180
180
  if not item['attributes']['release_year']:
@@ -184,14 +184,18 @@ class View(Torrent):
184
184
 
185
185
  media = f"[TRACKER] TMDB: {item['attributes']['tmdb_id']} - {release_year}"
186
186
 
187
+ elif item['attributes']['igdb_id'] !=0:
188
+ media = f"[TRACKER] IGDB: {item['attributes']['igdb_id']}"
187
189
  else:
188
- media = f"[TRACKER] IGDB: {item['attributes']['igdb_id']}"
190
+ media = f"[TRACKER] DOC:"
189
191
 
192
+ # Print a data to the console
190
193
  custom_console.bot_log(f"\n {media} - {item['attributes']['name']}")
194
+ # Save torrent data into database
195
+ self.database.write(item['attributes'])
191
196
 
192
197
 
193
-
194
- def page_view(self, tracker_data: dict, tracker: pvtTracker, info=False):
198
+ def page_view(self, tracker_data: dict, tracker: pvtTracker, info=False, inkey=True):
195
199
 
196
200
  self.print_normal(tracker_data) if not info else self.print_info(tracker_data)
197
201
  page = 0
@@ -199,12 +203,17 @@ class View(Torrent):
199
203
  if not tracker_data["links"]["next"]:
200
204
  break
201
205
 
206
+ # Wait for user input if inkey is True
202
207
  page += 1
203
- custom_console.bot_question_log(
204
- f"\n Prossima Pagina '{page}' - Premi un tasto per continuare, Q(quit) - "
205
- )
206
- if input().lower() == "q":
207
- break
208
+ if inkey:
209
+ custom_console.bot_question_log(
210
+ f"\n Prossima Pagina '{page}' - Premi un tasto per continuare, Q(quit) - "
211
+ )
212
+ if input().lower() == "q":
213
+ break
214
+ else:
215
+ # otherwise wait for 2 seconds ( 30 request/ 60sec max) dirty
216
+ time.sleep(2)
208
217
  print()
209
218
  custom_console.rule(f"\n[bold blue]'Page -> {page}'", style="#ea00d9")
210
219
  tracker_data = tracker.next(url=tracker_data["links"]["next"])
@@ -214,11 +223,11 @@ class View(Torrent):
214
223
  else self.print_info(tracker_data)
215
224
  )
216
225
 
217
- def view_search(self, keyword: str, info=False):
226
+ def view_search(self, keyword: str, info=False, inkey=True):
218
227
  tracker_data = self.search(keyword=keyword)
219
228
  custom_console.log(f"Searching.. '{keyword}'")
220
229
  (
221
- self.page_view(tracker_data=tracker_data, tracker=self.tracker)
230
+ self.page_view(tracker_data=tracker_data, tracker=self.tracker,inkey=inkey)
222
231
  if not info
223
232
  else self.page_view(
224
233
  tracker_data=tracker_data, tracker=self.tracker, info=True
File without changes
unit3dup/web/main.py ADDED
@@ -0,0 +1,46 @@
1
+ from fastapi import FastAPI, APIRouter
2
+ from random import randint
3
+ from common.torrent_clients import TransmissionClient, QbittorrentClient, RTorrentClient
4
+ from common.command import CommandLine
5
+ from common.settings import Load,DEFAULT_JSON_PATH
6
+
7
+ from unit3dup.torrent import View
8
+ from unit3dup import pvtTracker
9
+ from unit3dup.bot import Bot
10
+ from view import custom_console
11
+
12
+
13
+ import uvicorn
14
+ import argparse
15
+ from random import randint
16
+
17
+ app = FastAPI()
18
+
19
+ # Classe che gestisce gli endpoint
20
+ class WebApp:
21
+ def __init__(self, config: Load):
22
+ self.router = APIRouter()
23
+ self.numb = randint(0, 100)
24
+ self._setup_routes()
25
+
26
+ def _setup_routes(self):
27
+ # Add the endpoints
28
+ self.router.add_api_route("/", self.root, methods=["GET"])
29
+ self.router.add_api_route("/upload/{name}", self.upload, methods=["GET"])
30
+
31
+ async def root(self):
32
+ return {"message": f"Hello World {self.numb}"}
33
+
34
+ async def upload(self, name: str):
35
+
36
+
37
+
38
+ return {"message": f"Hello {name}, numb is {self.numb}"}
39
+
40
+
41
+ def web():
42
+ web_app = WebApp(config=Load().load_config())
43
+ app.include_router(web_app.router)
44
+ uvicorn.run("unit3dup.web.main:app", host="127.0.0.1", port=8000, reload=True)
45
+
46
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Unit3Dup
3
- Version: 0.8.7
3
+ Version: 0.8.9
4
4
  Summary: An uploader for the Unit3D torrent tracker
5
5
  Author: Parzival
6
6
  License-Expression: MIT
@@ -66,24 +66,19 @@ It performs the following tasks:
66
66
  unit3dup can grab the first page, convert it to an image (using xpdf),
67
67
  and then the bot can upload it to an image host, then add the link to the torrent page description.
68
68
 
69
- .. image:: https://img.shields.io/badge/INSTALL-gr
70
- :alt: install
71
69
 
72
- Ubuntu/Debian
73
- -------------
74
- pip install unit3dup
70
+ Install and Upgrade
71
+ ===================
75
72
 
76
- Upgrade
77
- -------
78
- pip install --upgrade unit3dup
73
+ - pip install unit3dup --upgrade
79
74
 
80
75
  Ubuntu/Debian Dependencies
81
76
  --------------------------
82
- sudo apt install ffmpeg
77
+ - sudo apt install ffmpeg
83
78
 
84
79
  Only for pdf
85
80
  ------------
86
- sudo apt install poppler-utils
81
+ - sudo apt install poppler-utils
87
82
 
88
83
 
89
84
  Windows Dependencies
@@ -110,12 +105,6 @@ Alternative method
110
105
  4. unit3dup
111
106
 
112
107
 
113
- .. image:: https://img.shields.io/badge/Bot_UPDATE-gr
114
- :alt: Bot Update
115
-
116
- 1. pip install unit3dup --upgrade
117
-
118
-
119
108
 
120
109
  RUN
121
110
  ======
@@ -1,25 +1,26 @@
1
1
  common/__init__.py,sha256=M82CDZm5KKWf8V3a10FKCy1wtFrJd1TMEhBib1Xtk1g,76
2
2
  common/bdinfo_string.py,sha256=dfrU5T90fvkO_fklvVNWSoCgd5qvrVvqEZ_HKEsHAU8,3457
3
3
  common/bittorrent.py,sha256=MPgMykWjmhGox7jf1MQn53Ew4NxpjzEc4FCF6oA2oYs,315
4
- common/command.py,sha256=UQ9MBSNzmdiT53JBr2cDTpowJPwHo8cCx9fxIljTvD4,5936
4
+ common/command.py,sha256=7QmtTFdawq2S70p9JP2dr2bGbAUdiTVnGFiNrBcz3R4,6029
5
5
  common/constants.py,sha256=tdflS7ZJwAcI1ZYUhBBb60QybVT7TmVS-EYxS4bNFp0,352
6
+ common/database.py,sha256=Lp6i3Wu5vza87atWD2NGQRCchVLBcY-k8E0AAuAQxls,3232
6
7
  common/extractor.py,sha256=WKZwt2kQfKO2VJ1rtwE_j6Zl84zICnowZq_Ql16wmRc,4564
7
8
  common/frames.py,sha256=p_jsaXII5tZTVt5ymu-w1hk2c_UMeOn3PZeuVR-wXWY,7973
8
9
  common/mediainfo.py,sha256=U2r1jJejBsV8GP3iPk4O8_NkHO5RQ9Kkh2bKwVNUBmg,6229
9
10
  common/mediainfo_string.py,sha256=8vuWlF2bqWRKpDbn81bV2fPA7hbl7RwOnxN2i4E3zNE,3958
10
- common/settings.py,sha256=ZMctg2CqpHNI4UJ3RnDI8Yn6BWkhMUOVsWgbDEwQTPQ,30518
11
+ common/settings.py,sha256=RPzMlRiYlqiuPd2hJO4w348R8GVERHhiA7V43t_pPug,32781
11
12
  common/title.py,sha256=nFainfUBTYW9ML4Y-CB9ZFD_Es-OZXcAMPUo6D09u3k,3793
12
13
  common/torrent_clients.py,sha256=NOIpYtLG_bA19HwcH9ahGFmGNtRkoMO6nAjma-JzDfs,12040
13
14
  common/utility.py,sha256=6VLhN4K8W9oJfYiHKK_nq5LGtbwHaSMjeojstoyqYfU,8575
14
15
  common/external_services/__init__.py,sha256=rU7HPEcZ7WQFD8eqDzuye2xHPBjxXPwPqpt7IT08mkM,178
15
- common/external_services/imageHost.py,sha256=-0lGHgkUskd2ySlgrJH5dhV2iebzo__9soxHvc5fxs4,8939
16
+ common/external_services/imageHost.py,sha256=BpdtGZUtZHl4QJwFKyJs_BI6z4gHI4wu_Beu-fnfkDw,9588
16
17
  common/external_services/imdb.py,sha256=AIo8CO-SfP_uNocDeNY08hpvCAnuotoI7hYUytDiMQA,579
17
18
  common/external_services/mediaresult.py,sha256=Yz-h7QROkfNHwaSSXZ1JRDSmG2YIZkmtQO5vmpkYWZ4,677
18
19
  common/external_services/Pw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- common/external_services/Pw/pw_manager.py,sha256=FW9uiKpiBIAu8O6LC-FhdIi4Dg2ycGVIRJsdvsNNbPs,1677
20
- common/external_services/Pw/pw_service.py,sha256=EmYl5UnMYj0DRR7B87u9gGXEl_i_eB8kHBVwJDZrirw,992
20
+ common/external_services/Pw/pw_manager.py,sha256=a8s3YgzHf0iw45Fh5BeMRSX5aGlatBJbOYamSrWFj2U,2225
21
+ common/external_services/Pw/pw_service.py,sha256=_-AQgffqiuoS0xcHc7sEgQBuXidU9RdJZyZnRa-ATZc,1151
21
22
  common/external_services/Pw/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- common/external_services/Pw/core/pw_api.py,sha256=M_jRE850x0hTSMGHrJ9M4yIGtIipAxScyKrTPKdJOg4,3434
23
+ common/external_services/Pw/core/pw_api.py,sha256=C1XzN-hJwJvzjZwiNTL39mu4gJGiEKKZYjt9JAStIHk,3234
23
24
  common/external_services/Pw/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
25
  common/external_services/Pw/core/models/indexers.py,sha256=7nVqZd-_nbwL40HLGEFauI8zNeC-w66py2tK7h9rGV4,1947
25
26
  common/external_services/Pw/core/models/search.py,sha256=fmoEccxgRDG26nmEcpJR0e5twBLTOEzDzaeQFG2TAc4,969
@@ -71,7 +72,7 @@ common/trackers/itt.py,sha256=DFXxrFX9i19kwGHfA1guswlBOueIHU00K-HvoperstA,4019
71
72
  common/trackers/sis.py,sha256=AahQH-FxAqS19vgEFylOJzeY0_SHr27_Tibs7lraSdI,3480
72
73
  common/trackers/trackers.py,sha256=uQgqmkJBoud4h8CWrc73yAURtkVU630sk1ZqLXJud7s,1384
73
74
  unit3dup/__init__.py,sha256=seXz3lHgdrUBiOnhC6Je47npS66UZ0c62VFuoH3z5Mk,78
74
- unit3dup/__main__.py,sha256=OX5n_8VcZYkq22R2BQp5yKAaFxVuNW9yMzL8mDC9MGM,9058
75
+ unit3dup/__main__.py,sha256=CDazL8WFGv_Y6y875s3Ej-0QK5MPytbTJm_vsPHWB-A,9270
75
76
  unit3dup/automode.py,sha256=HIJrE8qEHp7DZQbppNtB_8jHY3Q94d6frp7BXnZuEac,4387
76
77
  unit3dup/bot.py,sha256=TM8Htnq-udJDnN-7TwaPP6CiwWX0wb_Nud9p8ej8GRo,9250
77
78
  unit3dup/duplicate.py,sha256=Ji1Y9vVLmhFQ5rgkUU-s7uXl-jC8akAa8OiQOfjFa9g,10428
@@ -81,7 +82,7 @@ unit3dup/pvtDocu.py,sha256=ZLMaal2fn6ZcFPLtET0LTmYEPjhJmLitEjkICHrm9CQ,4594
81
82
  unit3dup/pvtTorrent.py,sha256=cItlsCpcUJL23iXQHy0YzrrvV3JSl54UlBgm8_UROAs,2559
82
83
  unit3dup/pvtTracker.py,sha256=U4xMmhiqMNZaIOgEi3pnP-3H75e7Gagndh8GDFEP7Cs,18647
83
84
  unit3dup/pvtVideo.py,sha256=w_T6wEeGrsHkuR3KObJc4mNpJgg9hhHh_9LoxFlaqjM,3900
84
- unit3dup/torrent.py,sha256=zbaplTKKgZ2w12jtD60ne9XvlkauDpjT2BRxa4WvWWU,19318
85
+ unit3dup/torrent.py,sha256=JEcrVG8dlYASBvL51GldU1ouKlfieKccKX2KZ_4UKBY,19883
85
86
  unit3dup/upload.py,sha256=gjB8u2oP2FPXZ8t9SMIzkUEr52hKRy_zSR8OWJlW2xc,6075
86
87
  unit3dup/media_manager/ContentManager.py,sha256=X0nepb-PgBzTasnw-Z_Vz11oq8-66kg_5Q0Eddn964g,7123
87
88
  unit3dup/media_manager/DocuManager.py,sha256=oFt7jlxj-gIUty9PADBQV5a24bsv3yhjKhwI6niOhf4,3116
@@ -92,11 +93,13 @@ unit3dup/media_manager/TorrentManager.py,sha256=qqM1d1TyfBuruXtKLRbQ8gFk3_2JNH9d
92
93
  unit3dup/media_manager/VideoManager.py,sha256=O1NzGnWiWPfMgjyV6h9_b9b8M5tzFtpje9cvI2g6Nc0,5437
93
94
  unit3dup/media_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
95
  unit3dup/media_manager/common.py,sha256=hG2zOw7ocQfZyI1dhusbehxswpIrZK7T2aAbCNwULqA,10138
95
- unit3dup-0.8.7.dist-info/licenses/LICENSE,sha256=GNAZDLhU0xz8QPbIyHAOYlVnQYDvKWk2N9fZJMhqaG8,1090
96
+ unit3dup/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
+ unit3dup/web/main.py,sha256=BzjKDgAjKZMnoQwx7nDDbs_64kCrFO1VYpbHmsGiFVc,1267
98
+ unit3dup-0.8.9.dist-info/licenses/LICENSE,sha256=GNAZDLhU0xz8QPbIyHAOYlVnQYDvKWk2N9fZJMhqaG8,1090
96
99
  view/__init__.py,sha256=XIzb6rl58HmYPnksD73cYMFF88dn6FHa3u7bOHFbChk,81
97
- view/custom_console.py,sha256=QD7LjVi7qoBCZ9RpXxsouLfkGtRq-d5yVIQem2Q0SdI,4741
98
- unit3dup-0.8.7.dist-info/METADATA,sha256=93vhjheaMvSYym49SAAx7fa5q9ChbPzgX07kYrayIJU,5224
99
- unit3dup-0.8.7.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
100
- unit3dup-0.8.7.dist-info/entry_points.txt,sha256=fxXSyI6-r6jy9_v-C5ZHm03q1aC3tE9EvCQZxC1NQnI,52
101
- unit3dup-0.8.7.dist-info/top_level.txt,sha256=19NVMnQNkJxBUKebRNaYCRs56A5CO4U1L67GMQCPiLU,21
102
- unit3dup-0.8.7.dist-info/RECORD,,
100
+ view/custom_console.py,sha256=OITmkEoQH9N_uE5ElPaSdc8XvaLzE9wcwTbOHtcMvrI,5629
101
+ unit3dup-0.8.9.dist-info/METADATA,sha256=fTipWVLGNyAyrtT48e7V-1jcFl-UORYn4oUzXzzszL4,5015
102
+ unit3dup-0.8.9.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
103
+ unit3dup-0.8.9.dist-info/entry_points.txt,sha256=fxXSyI6-r6jy9_v-C5ZHm03q1aC3tE9EvCQZxC1NQnI,52
104
+ unit3dup-0.8.9.dist-info/top_level.txt,sha256=19NVMnQNkJxBUKebRNaYCRs56A5CO4U1L67GMQCPiLU,21
105
+ unit3dup-0.8.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
view/custom_console.py CHANGED
@@ -69,6 +69,31 @@ class CustomConsole(Console):
69
69
 
70
70
  self.print(Align.center(table))
71
71
 
72
+ def bot_process_table_pw(self, content: list):
73
+
74
+ table = Table(
75
+ title="Here is your files list" if content else "There are no files here",
76
+ border_style="bold blue",
77
+ header_style="red blue",
78
+ )
79
+
80
+ table.add_column("Category", style="dim")
81
+ table.add_column("Indexer", justify="left", style="bold green")
82
+ table.add_column("Title", justify="left", style="bold green")
83
+ table.add_column("Size", justify="left", style="bold green")
84
+ table.add_column("Seeders", justify="left", style="bold green")
85
+
86
+ for item in content:
87
+ table.add_row(
88
+ item.categories[0]['name'],
89
+ item.indexer,
90
+ item.title,
91
+ str(item.size),
92
+ str(item.seeders),
93
+ )
94
+
95
+ self.print(Align.center(table))
96
+
72
97
  def bot_tmdb_table_log(self, result, title: str, media_info_language: str):
73
98
 
74
99
  self.print("\n")