Yuuki0125 commited on
Commit
7432086
·
1 Parent(s): f6c6f0c
Files changed (5) hide show
  1. Dockerfile +11 -0
  2. functions.py +471 -0
  3. main.py +27 -0
  4. phdler.py +55 -0
  5. requirements.txt +7 -0
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10.9
2
+
3
+ WORKDIR /code
4
+
5
+ COPY ./requirements.txt /code/requirements.txt
6
+
7
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
8
+
9
+ COPY . .
10
+
11
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
functions.py ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ import youtube_dl
3
+ import requests
4
+ import sys
5
+ import urllib.parse as urlparse
6
+ import sqlite3
7
+ import os
8
+ from prettytable import PrettyTable
9
+ from sqlite3 import Error
10
+ from urllib import request
11
+ from bs4 import BeautifulSoup
12
+
13
+ # Database location
14
+ database = "./tmp/database.db"
15
+
16
+
17
+ # CHECKINGS
18
+ def type_check(item):
19
+ if item == "model":
20
+ print("Valid type (model) selected.")
21
+ elif item == "pornstar":
22
+ print("Valid type (pornstar) selected.")
23
+ elif item == "channels":
24
+ print("Valid type (channel) selected.")
25
+ elif item == "users":
26
+ print("Valid type (user) selected.")
27
+ elif item == "playlist":
28
+ print("Valid type (playlist) selected.")
29
+ elif item == "all":
30
+ print("Valid type (all) selected.")
31
+ else:
32
+ how_to_use("Not a valid type.")
33
+ sys.exit()
34
+
35
+
36
+ def ph_url_check(url):
37
+ parsed = urlparse.urlparse(url)
38
+ regions = ["www", "cn", "cz", "de", "es", "fr", "it", "nl", "jp", "pt", "pl", "rt"]
39
+ for region in regions:
40
+ if parsed.netloc == region + ".pornhub.com":
41
+ print("PornHub url validated.")
42
+ return
43
+ print("This is not a PornHub url.")
44
+ sys.exit()
45
+
46
+
47
+ def ph_type_check(url):
48
+ parsed = urlparse.urlparse(url)
49
+ if parsed.path.split('/')[1] == "model":
50
+ print("This is a MODEL url,")
51
+ elif parsed.path.split('/')[1] == "pornstar":
52
+ print("This is a PORNSTAR url,")
53
+ elif parsed.path.split('/')[1] == "channels":
54
+ print("This is a CHANNEL url,")
55
+ elif parsed.path.split('/')[1] == "users":
56
+ print("This is a USER url,")
57
+ elif parsed.path.split('/')[1] == "playlist":
58
+ print("This is a PLAYLIST url,")
59
+ elif parsed.path.split('/')[1] == "view_video.php":
60
+ print("This is a VIDEO url. Please paste a model/pornstar/user/channel/playlist url.")
61
+ sys.exit()
62
+ else:
63
+ print("Somethings wrong with the url. Please check it out.")
64
+ sys.exit()
65
+
66
+
67
+ def ph_alive_check(url):
68
+ requested = requests.get(url)
69
+ if requested.status_code == 200:
70
+ print("and the URL is existing.")
71
+ else:
72
+ print("but the URL does not exist.")
73
+ sys.exit()
74
+
75
+
76
+ def add_check(name_check):
77
+ if name_check == "batch":
78
+ u_input = input("Please enter full path to the batch-file.txt (or c to cancel): ")
79
+ if u_input == "c":
80
+ print("Operation canceled.")
81
+ else:
82
+ with open(u_input, 'r') as input_file:
83
+ for line in input_file:
84
+ line = line.strip()
85
+ add_item(line)
86
+
87
+ else:
88
+ add_item(name_check)
89
+
90
+
91
+ def get_item_name(item_type, url_item):
92
+ url = url_item
93
+ html = request.urlopen(url).read().decode('utf8')
94
+ soup = BeautifulSoup(html, 'lxml')
95
+
96
+ if item_type == "model":
97
+ finder = soup.find(class_='nameSubscribe')
98
+ title = finder.find(itemprop='name').text.replace('\n', '').strip()
99
+ elif item_type == "pornstar":
100
+ finder = soup.find(class_='nameSubscribe')
101
+ title = finder.find(class_='name').text.replace('\n', '').strip()
102
+ elif item_type == "channels":
103
+ finder = soup.find(class_='bottomExtendedWrapper')
104
+ title = finder.find(class_='title').text.replace('\n', '').strip()
105
+ elif item_type == "users":
106
+ finder = soup.find(class_='bottomInfoContainer')
107
+ title = finder.find('a', class_='float-left').text.replace('\n', '').strip()
108
+ elif item_type == "playlist":
109
+ finder = soup.find(id='playlistTopHeader')
110
+ title = finder.find(id='watchPlaylist').text.replace('\n', '').strip()
111
+ else:
112
+ print("No valid item type.")
113
+ title = False
114
+
115
+ return title
116
+
117
+
118
+ ##################################### DOWNLOADING
119
+
120
+
121
+ def dl_all_items(conn):
122
+ c = conn.cursor()
123
+ try:
124
+ c.execute("SELECT * FROM ph_items")
125
+ except Error as e:
126
+ print(e)
127
+ sys.exit()
128
+
129
+ rows = c.fetchall()
130
+
131
+ for row in rows:
132
+ if row[1] == "model":
133
+ url_after = "/videos/upload"
134
+ # elif row[1] == "pornstar":
135
+ # url_after = "/"
136
+ elif row[1] == "users":
137
+ url_after = "/videos/public"
138
+ elif row[1] == "channels":
139
+ url_after = "/videos"
140
+ else:
141
+ url_after = ""
142
+
143
+ print("-----------------------------")
144
+ print(row[1])
145
+ print(row[2])
146
+ print("https://www.pornhub.com/" + str(row[1]) + "/" + str(row[2]) + url_after)
147
+ print("-----------------------------")
148
+
149
+ # Find more available options here: https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/YoutubeDL.py#L129-L279
150
+ outtmpl = get_dl_location('DownloadLocation') + '/' + str(row[1]) + '/' + str(row[3]) + '/%(title)s.%(ext)s'
151
+ ydl_opts_start = {
152
+ 'format': 'best',
153
+ 'playliststart:': 1,
154
+ 'playlistend': 4,
155
+ 'outtmpl': outtmpl,
156
+ 'nooverwrites': True,
157
+ 'no_warnings': False,
158
+ 'ignoreerrors': True,
159
+ }
160
+
161
+ url = "https://www.pornhub.com/" + str(row[1]) + "/" + str(row[2] + url_after)
162
+ with youtube_dl.YoutubeDL(ydl_opts_start) as ydl:
163
+ ydl.download([url])
164
+
165
+ try:
166
+ c.execute("UPDATE ph_items SET lastchecked=CURRENT_TIMESTAMP WHERE url_name = ?", (row[2],))
167
+ conn.commit()
168
+ except Error as e:
169
+ print(e)
170
+ sys.exit()
171
+
172
+
173
+ def dl_all_new_items(conn):
174
+ c = conn.cursor()
175
+ try:
176
+ c.execute("SELECT * FROM ph_items WHERE new='1'")
177
+ except Error as e:
178
+ print(e)
179
+ sys.exit()
180
+
181
+ rows = c.fetchall()
182
+
183
+ for row in rows:
184
+
185
+ if str(row[1]) == "model":
186
+ url_after = "/videos/upload"
187
+ # elif str(row[1]) == "pornstar":
188
+ # url_after = "/videos"
189
+ elif str(row[1]) == "users":
190
+ url_after = "/videos/public"
191
+ elif str(row[1]) == "channels":
192
+ url_after = "/videos"
193
+ else:
194
+ url_after = ""
195
+
196
+ print("-----------------------------")
197
+ print(row[1])
198
+ print(row[2])
199
+ print("https://www.pornhub.com/" + str(row[1]) + "/" + str(row[2]) + url_after)
200
+ print("-----------------------------")
201
+
202
+ # Find more available options here: https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/YoutubeDL.py#L129-L279
203
+ outtmpl = get_dl_location('DownloadLocation') + '/' + str(row[1]) + '/' + str(row[3]) + '/%(title)s.%(ext)s'
204
+ ydl_opts = {
205
+ 'format': 'best',
206
+ 'outtmpl': outtmpl,
207
+ 'nooverwrites': True,
208
+ 'no_warnings': False,
209
+ 'ignoreerrors': True,
210
+ }
211
+
212
+ url = "https://www.pornhub.com/" + str(row[1]) + "/" + str(row[2]) + url_after
213
+ with youtube_dl.YoutubeDL(ydl_opts) as ydl:
214
+ ydl.download([url])
215
+
216
+ try:
217
+ c.execute("UPDATE ph_items SET new='0', lastchecked=CURRENT_TIMESTAMP WHERE url_name=?", (row[2],))
218
+ conn.commit()
219
+ except Error as e:
220
+ print(e)
221
+ sys.exit()
222
+
223
+
224
+ def dl_start():
225
+ conn = create_connection(database)
226
+ with conn:
227
+ print("downloading new items")
228
+ dl_all_new_items(conn)
229
+ print("downloading all items")
230
+ dl_all_items(conn)
231
+
232
+
233
+ def custom_dl(name_check):
234
+ if name_check == "batch":
235
+ u_input = input("Please enter full path to the batch-file.txt (or c to cancel): ")
236
+ if u_input == "c":
237
+ print("Operation canceled.")
238
+ else:
239
+ with open(u_input, 'r') as input_file:
240
+ for line in input_file:
241
+ line = line.strip()
242
+ custom_dl_download(line)
243
+
244
+ else:
245
+ custom_dl_download(name_check)
246
+
247
+
248
+ def custom_dl_download(url):
249
+ ph_url_check(url)
250
+ ph_alive_check(url)
251
+
252
+ outtmpl = get_dl_location('DownloadLocation') + '/media/%(title)s.%(ext)s'
253
+ ydl_opts = {
254
+ 'format': 'best',
255
+ 'outtmpl': outtmpl,
256
+ 'nooverwrites': True,
257
+ 'no_warnings': False,
258
+ 'ignoreerrors': True,
259
+ }
260
+
261
+ with youtube_dl.YoutubeDL(ydl_opts) as ydl:
262
+ ydl.download([url])
263
+
264
+
265
+ def add_item(name_check):
266
+ parsed = urlparse.urlparse(name_check)
267
+ ph_url_check(name_check)
268
+ ph_type_check(name_check)
269
+ ph_alive_check(name_check)
270
+ item_type = parsed.path.split('/')[1]
271
+ item_url_name = parsed.path.split('/')[2]
272
+ item_name = get_item_name(item_type, name_check)
273
+
274
+ conn = create_connection(database)
275
+ c = conn.cursor()
276
+ try:
277
+ c.execute("SELECT count(*) FROM ph_items WHERE url_name = ?", (item_name,))
278
+ except Error as e:
279
+ print(e)
280
+ sys.exit()
281
+
282
+ data = c.fetchone()[0]
283
+ if data == 0:
284
+ with conn:
285
+ item = (item_type, item_url_name, item_name, '1')
286
+ create_item(conn, item)
287
+ print(item_name + " added to database.")
288
+ else:
289
+ print("Item already exists in database")
290
+
291
+
292
+ ##################################### DATABASE ORIENTED
293
+
294
+ def create_connection(db_file):
295
+ conn = None
296
+ try:
297
+ conn = sqlite3.connect(db_file)
298
+ except Error as e:
299
+ print(e)
300
+ return conn
301
+
302
+
303
+ def create_item(conn, item):
304
+ sql = ''' INSERT INTO ph_items(type,url_name,name,new)
305
+ VALUES(?,?,?,?) '''
306
+ c = conn.cursor()
307
+ c.execute(sql, item)
308
+ return c.lastrowid
309
+
310
+
311
+ def select_all_items(conn, item):
312
+ c = conn.cursor()
313
+ if item == "all":
314
+ c.execute("SELECT * FROM ph_items")
315
+ else:
316
+ c.execute("SELECT * FROM ph_items WHERE type='" + item + "'")
317
+
318
+ rows = c.fetchall()
319
+
320
+ t = PrettyTable(['Id.', 'Name', 'Type', 'Date created', 'Last checked', 'Url'])
321
+ t.align['Id.'] = "l"
322
+ t.align['Name'] = "l"
323
+ t.align['Type'] = "l"
324
+ t.align['Date created'] = "l"
325
+ t.align['Last checked'] = "l"
326
+ t.align['Url'] = "l"
327
+ for row in rows:
328
+ url = "https://www.pornhub.com/" + str(row[1]) + "/" + str(row[2])
329
+ t.add_row([row[0], row[3], row[1], row[5], row[6], url])
330
+ print(t)
331
+
332
+
333
+ def list_items(item):
334
+ conn = create_connection(database)
335
+ with conn:
336
+ print("Listing items from database:")
337
+ select_all_items(conn, item)
338
+
339
+
340
+ def delete_single_item(conn, id):
341
+ sql = 'DELETE FROM ph_items WHERE id=?'
342
+ c = conn.cursor()
343
+ c.execute(sql, (id,))
344
+ conn.commit()
345
+
346
+
347
+ def delete_item(item_id):
348
+ conn = create_connection(database)
349
+ with conn:
350
+ delete_single_item(conn, item_id)
351
+
352
+
353
+ def create_config(conn, item):
354
+ sql = ''' INSERT INTO ph_settings(option, setting)
355
+ VALUES(?,?) '''
356
+ c = conn.cursor()
357
+ c.execute(sql, item)
358
+ return c.lastrowid
359
+
360
+
361
+ def prepare_config():
362
+ conn = create_connection(database)
363
+ u_input = input("Please enter the FULL PATH to your download location: ")
364
+ with conn:
365
+ item = ('DownloadLocation', u_input)
366
+ item_id = create_config(conn, item)
367
+
368
+
369
+ def get_dl_location(option):
370
+ conn = create_connection(database)
371
+ if conn is not None:
372
+ c = conn.cursor()
373
+ c.execute("SELECT * FROM ph_settings WHERE option='" + option + "'")
374
+ rows = c.fetchall()
375
+ for row in rows:
376
+ dllocation = row[2]
377
+ return dllocation if dllocation else './tmp' # Set your default folder here
378
+ else:
379
+ print("Error! something's wrong with the query.")
380
+
381
+
382
+ def check_for_database():
383
+ print("Running startup checks...")
384
+ if os.path.exists(database):
385
+ print("Database exists.")
386
+ else:
387
+ print("Database does not exist.")
388
+ print("Looks like this is your first time run...")
389
+ first_run()
390
+
391
+
392
+ def create_table(conn, create_table_sql):
393
+ try:
394
+ c = conn.cursor()
395
+ c.execute(create_table_sql)
396
+ print("Tables created.")
397
+ except Error as e:
398
+ print(e)
399
+
400
+
401
+ def create_tables():
402
+ sql_create_items_table = """ CREATE TABLE IF NOT EXISTS ph_items (
403
+ id integer PRIMARY KEY,
404
+ type text,
405
+ url_name text,
406
+ name text,
407
+ new integer DEFAULT 1,
408
+ datecreated DATETIME DEFAULT CURRENT_TIMESTAMP,
409
+ lastchecked DATETIME DEFAULT CURRENT_TIMESTAMP
410
+ ); """
411
+
412
+ sql_create_settings_table = """ CREATE TABLE IF NOT EXISTS ph_settings (
413
+ id integer PRIMARY KEY,
414
+ option text,
415
+ setting text,
416
+ datecreated DATETIME DEFAULT CURRENT_TIMESTAMP
417
+ ); """
418
+
419
+ # create a database connection
420
+ conn = create_connection(database)
421
+
422
+ # create tables
423
+ if conn is not None:
424
+ # create items table
425
+ create_table(conn, sql_create_items_table)
426
+ create_table(conn, sql_create_settings_table)
427
+ prepare_config()
428
+ else:
429
+ print("Error! cannot create the database connection.")
430
+
431
+
432
+ ##################################### Lets do it baby
433
+
434
+ def first_run():
435
+ create_tables()
436
+
437
+
438
+ ##################################### MESSAGING
439
+
440
+
441
+ def how_to_use(error):
442
+ print("Error: " + error)
443
+ print("Please use the tool like this:")
444
+ t = PrettyTable(['Tool', 'command', 'item'])
445
+ t.align['Tool'] = "l"
446
+ t.align['command'] = "l"
447
+ t.align['item'] = "l"
448
+ t.add_row(['phdler', 'start', ''])
449
+ t.add_row(['phdler', 'custom', 'url (full PornHub url) | batch (for .txt file)'])
450
+ t.add_row(['phdler', 'add', 'model | pornstar | channel | user | playlist | batch (for .txt file)'])
451
+ t.add_row(['phdler', 'list', 'model | pornstar | channel | user | playlist | all'])
452
+ t.add_row(['phdler', 'delete', 'model | pornstar | channel | user | playlist'])
453
+ print(t)
454
+
455
+
456
+ def help_command():
457
+ print("------------------------------------------------------------------")
458
+ print("You asked for help, here it comes! Run phdler with these commands:")
459
+ t = PrettyTable(['Command', 'argument', 'description'])
460
+ t.align['Command'] = "l"
461
+ t.align['argument'] = "l"
462
+ t.align['description'] = "l"
463
+ t.add_row(['start', '', 'start the script'])
464
+ t.add_row(['custom', 'url | batch', 'download a single video from PornHub'])
465
+ t.add_row(
466
+ ['add', 'model | pornstar | channel | user | playlist | batch (for .txt file)', 'adding item to database'])
467
+ t.add_row(['list', 'model | pornstar | channel | user | playlist', 'list selected items from database'])
468
+ t.add_row(['delete', 'model | pornstar | channel | user | playlist', 'delete selected items from database'])
469
+ print(t)
470
+ print("Example: phdler add pornhub-url")
471
+ print("------------------------------------------------------------------")
main.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import FileResponse
3
+ import subprocess
4
+
5
+ app = FastAPI()
6
+
7
+ phdler_path = 'phdler.py'
8
+
9
+ @app.get("/AnotherAPI/{api_key}/PH/Downloader/{url_ph}")
10
+ async def download_video(api_key: str, url_ph: str):
11
+ url = url_ph
12
+ API = (api_key)
13
+ if API == api_key:
14
+ try:
15
+ subprocess.run(['python', phdler_path, 'custom', url], check=True)
16
+ file_name = "PH.mp4"
17
+ file_path = f"/tmp/media/{file_name}"
18
+ return FileResponse(file_path, filename=file_name, media_type="application/mp4")
19
+ except subprocess.CalledProcessError as e:
20
+ raise HTTPException(status_code=500, detail=f"Error: {e}")
21
+ else:
22
+ return {"respon": "API Lu Mana?"}
23
+
24
+ if __name__ == "__main__":
25
+ import uvicorn
26
+
27
+ uvicorn.run(app, host="127.0.0.1", port=8000)
phdler.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ from functions import *
3
+
4
+ def main():
5
+
6
+ check_for_database()
7
+
8
+ if len(sys.argv) > 1:
9
+
10
+ if sys.argv[1] == "start":
11
+ dl_start()
12
+
13
+ elif sys.argv[1] == "custom":
14
+ if len(sys.argv) > 2:
15
+ custom_dl(sys.argv[2])
16
+ else:
17
+ how_to_use("Missing item")
18
+
19
+ elif sys.argv[1] == "add":
20
+ if len(sys.argv) > 2:
21
+ add_check(sys.argv[2])
22
+ else:
23
+ how_to_use("Missing item")
24
+
25
+ elif sys.argv[1] == "delete":
26
+ if len(sys.argv) > 2:
27
+ type_check(sys.argv[2])
28
+ list_items(sys.argv[2])
29
+ u_input = input("Please enter the ID to delete (or c to cancel): ")
30
+ if u_input == "c":
31
+ print("Operation canceled.")
32
+ else:
33
+ delete_item(u_input)
34
+ else:
35
+ how_to_use("Missing item")
36
+
37
+ elif sys.argv[1] == "list":
38
+ if len(sys.argv) > 2:
39
+ type_check(sys.argv[2])
40
+ list_items(sys.argv[2])
41
+ else:
42
+ how_to_use("Missing item")
43
+
44
+ elif sys.argv[1] == "help":
45
+ help_command()
46
+
47
+ else:
48
+ how_to_use("Command not found!")
49
+
50
+ else:
51
+ how_to_use("Missing command.")
52
+
53
+
54
+ if __name__ == '__main__':
55
+ main()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ youtube_dl
4
+ beautifulsoup4
5
+ lxml
6
+ requests
7
+ prettytable