Unit3Dup 0.8.7__tar.gz → 0.8.9__tar.gz

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 Unit3Dup might be problematic. Click here for more details.

Files changed (112) hide show
  1. {unit3dup-0.8.7 → unit3dup-0.8.9}/PKG-INFO +6 -17
  2. {unit3dup-0.8.7 → unit3dup-0.8.9}/README.rst +5 -16
  3. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/PKG-INFO +6 -17
  4. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/SOURCES.txt +3 -0
  5. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/top_level.txt +1 -0
  6. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/command.py +1 -0
  7. unit3dup-0.8.9/common/database.py +94 -0
  8. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/pw_api.py +6 -9
  9. unit3dup-0.8.9/common/external_services/Pw/pw_manager.py +63 -0
  10. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/pw_service.py +7 -2
  11. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/imageHost.py +23 -3
  12. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/settings.py +73 -11
  13. {unit3dup-0.8.7 → unit3dup-0.8.9}/pyproject.toml +1 -1
  14. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/__main__.py +10 -2
  15. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/torrent.py +24 -15
  16. unit3dup-0.8.9/unit3dup/web/__init__.py +0 -0
  17. unit3dup-0.8.9/unit3dup/web/main.py +46 -0
  18. {unit3dup-0.8.7 → unit3dup-0.8.9}/view/custom_console.py +25 -0
  19. unit3dup-0.8.7/common/external_services/Pw/pw_manager.py +0 -46
  20. {unit3dup-0.8.7 → unit3dup-0.8.9}/LICENSE +0 -0
  21. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/dependency_links.txt +0 -0
  22. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/entry_points.txt +0 -0
  23. {unit3dup-0.8.7 → unit3dup-0.8.9}/Unit3Dup.egg-info/requires.txt +0 -0
  24. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/__init__.py +0 -0
  25. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/bdinfo_string.py +0 -0
  26. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/bittorrent.py +0 -0
  27. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/constants.py +0 -0
  28. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/__init__.py +0 -0
  29. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/__init__.py +0 -0
  30. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/models/__init__.py +0 -0
  31. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/models/indexers.py +0 -0
  32. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/models/search.py +0 -0
  33. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/Pw/core/models/torrent_client_config.py +0 -0
  34. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/__init__.py +0 -0
  35. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/__init__.py +0 -0
  36. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/client.py +0 -0
  37. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/__init__.py +0 -0
  38. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/ftpx_service.py +0 -0
  39. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/ftpx_session.py +0 -0
  40. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/menu.py +0 -0
  41. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/models/__init__.py +0 -0
  42. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/ftpx/core/models/list.py +0 -0
  43. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/__init__.py +0 -0
  44. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/client.py +0 -0
  45. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/__init__.py +0 -0
  46. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/api.py +0 -0
  47. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/models/__init__.py +0 -0
  48. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/models/search.py +0 -0
  49. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/platformid.py +0 -0
  50. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/igdb/core/tags.py +0 -0
  51. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/imdb.py +0 -0
  52. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/mediaresult.py +0 -0
  53. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/sessions/__init__.py +0 -0
  54. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/sessions/agents.py +0 -0
  55. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/sessions/exceptions.py +0 -0
  56. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/sessions/session.py +0 -0
  57. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/__init__.py +0 -0
  58. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/__init__.py +0 -0
  59. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/api.py +0 -0
  60. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/keywords.py +0 -0
  61. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/__init__.py +0 -0
  62. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/__init__.py +0 -0
  63. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/alternative_titles.py +0 -0
  64. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/details.py +0 -0
  65. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/movie.py +0 -0
  66. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/nowplaying.py +0 -0
  67. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/movie/release_info.py +0 -0
  68. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/__init__.py +0 -0
  69. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/alternative.py +0 -0
  70. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/details.py +0 -0
  71. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/on_the_air.py +0 -0
  72. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/translations.py +0 -0
  73. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/models/tvshow/tvshow.py +0 -0
  74. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/theMovieDB/core/videos.py +0 -0
  75. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/trailers/__init__.py +0 -0
  76. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/trailers/api.py +0 -0
  77. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/external_services/trailers/response.py +0 -0
  78. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/extractor.py +0 -0
  79. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/frames.py +0 -0
  80. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/mediainfo.py +0 -0
  81. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/mediainfo_string.py +0 -0
  82. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/title.py +0 -0
  83. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/torrent_clients.py +0 -0
  84. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/trackers/__init__.py +0 -0
  85. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/trackers/data.py +0 -0
  86. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/trackers/itt.py +0 -0
  87. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/trackers/sis.py +0 -0
  88. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/trackers/trackers.py +0 -0
  89. {unit3dup-0.8.7 → unit3dup-0.8.9}/common/utility.py +0 -0
  90. {unit3dup-0.8.7 → unit3dup-0.8.9}/requirements.txt +0 -0
  91. {unit3dup-0.8.7 → unit3dup-0.8.9}/setup.cfg +0 -0
  92. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/__init__.py +0 -0
  93. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/automode.py +0 -0
  94. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/bot.py +0 -0
  95. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/duplicate.py +0 -0
  96. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/exceptions.py +0 -0
  97. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media.py +0 -0
  98. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/ContentManager.py +0 -0
  99. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/DocuManager.py +0 -0
  100. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/GameManager.py +0 -0
  101. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/MediaInfoManager.py +0 -0
  102. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/SeedManager.py +0 -0
  103. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/TorrentManager.py +0 -0
  104. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/VideoManager.py +0 -0
  105. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/__init__.py +0 -0
  106. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/media_manager/common.py +0 -0
  107. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/pvtDocu.py +0 -0
  108. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/pvtTorrent.py +0 -0
  109. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/pvtTracker.py +0 -0
  110. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/pvtVideo.py +0 -0
  111. {unit3dup-0.8.7 → unit3dup-0.8.9}/unit3dup/upload.py +0 -0
  112. {unit3dup-0.8.7 → unit3dup-0.8.9}/view/__init__.py +0 -0
@@ -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
  ======
@@ -35,24 +35,19 @@ It performs the following tasks:
35
35
  unit3dup can grab the first page, convert it to an image (using xpdf),
36
36
  and then the bot can upload it to an image host, then add the link to the torrent page description.
37
37
 
38
- .. image:: https://img.shields.io/badge/INSTALL-gr
39
- :alt: install
40
38
 
41
- Ubuntu/Debian
42
- -------------
43
- pip install unit3dup
39
+ Install and Upgrade
40
+ ===================
44
41
 
45
- Upgrade
46
- -------
47
- pip install --upgrade unit3dup
42
+ - pip install unit3dup --upgrade
48
43
 
49
44
  Ubuntu/Debian Dependencies
50
45
  --------------------------
51
- sudo apt install ffmpeg
46
+ - sudo apt install ffmpeg
52
47
 
53
48
  Only for pdf
54
49
  ------------
55
- sudo apt install poppler-utils
50
+ - sudo apt install poppler-utils
56
51
 
57
52
 
58
53
  Windows Dependencies
@@ -79,12 +74,6 @@ Alternative method
79
74
  4. unit3dup
80
75
 
81
76
 
82
- .. image:: https://img.shields.io/badge/Bot_UPDATE-gr
83
- :alt: Bot Update
84
-
85
- 1. pip install unit3dup --upgrade
86
-
87
-
88
77
 
89
78
  RUN
90
79
  ======
@@ -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
  ======
@@ -13,6 +13,7 @@ common/bdinfo_string.py
13
13
  common/bittorrent.py
14
14
  common/command.py
15
15
  common/constants.py
16
+ common/database.py
16
17
  common/extractor.py
17
18
  common/frames.py
18
19
  common/mediainfo.py
@@ -102,5 +103,7 @@ unit3dup/media_manager/TorrentManager.py
102
103
  unit3dup/media_manager/VideoManager.py
103
104
  unit3dup/media_manager/__init__.py
104
105
  unit3dup/media_manager/common.py
106
+ unit3dup/web/__init__.py
107
+ unit3dup/web/main.py
105
108
  view/__init__.py
106
109
  view/custom_console.py
@@ -3,5 +3,6 @@ common
3
3
  dist
4
4
  docs
5
5
  tests
6
+ tracker_cache
6
7
  unit3dup
7
8
  view
@@ -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")
@@ -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."""
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import argparse
4
+ import os
5
+
6
+ from common.external_services.Pw.pw_service import PwService
7
+ from common.utility import ManageTitles
8
+ from common.database import Database
9
+ from common import config_settings
10
+ from unit3dup.media import Media
11
+
12
+
13
+ from qbittorrent import Client
14
+ from view import custom_console
15
+
16
+ class PwManager:
17
+
18
+ def __init__(self,cli: argparse.Namespace):
19
+ # Keyword
20
+ self.search = cli.pw
21
+
22
+ # filename for the new download
23
+ self.filename = ManageTitles.normalize_filename(self.search)
24
+
25
+ # Select the tracker database
26
+ self.database = Database(db_file=cli.tracker)
27
+
28
+
29
+ def process(self):
30
+
31
+ # a new qbittorrent instance
32
+ qb = Client(f"http://{config_settings.torrent_client_config.QBIT_HOST}:{config_settings.torrent_client_config.QBIT_PORT}/")
33
+ # a new pw instance
34
+ pw_service = PwService()
35
+ # Query the indexers
36
+ search = pw_service.search(query=self.search)
37
+
38
+ content = []
39
+ if search:
40
+ for index, s in enumerate(search):
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
@@ -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 !")
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  dynamic = ["dependencies"]
7
7
  name = "Unit3Dup"
8
- version = "0.8.7"
8
+ version = "0.8.9"
9
9
  description = "An uploader for the Unit3D torrent tracker"
10
10
  readme = "README.rst"
11
11
  requires-python = ">=3.10"
@@ -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