-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
1119 lines (809 loc) · 37.6 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
try:
from flask import Flask, render_template, request, jsonify, session, send_file, send_from_directory, abort, redirect, url_for
#print("imported flask")
import os
#print("imported os")
import re
#print("imported re")
import requests
#print("imported requests")
import json
#print("imported json")
import urllib.parse
#print("imported urllib.parse")
from dotenv import load_dotenv
#print("imported load_dotenv")
import urllib
#print("imported urllib")
import WebScrapers.OnSite.UPDATE
#print("imported webscrapers.update")
from WebScrapers.Required.replaceCode import replace_special_characters
#print("imported replace_special_characters")
import WebScrapers.OnSite.mangaReaderDotOrg
#print("imported WebScrapers.OnSite.mangaReaderDotOrg")
import WebScrapers.OnSite.manhwaClanDotCom
#print('imported WebScrapers.OnSite.manhwaClan')
import WebScrapers.OnSite.readBerserkDotCom
#print('imported WebScrapers.OnSite.readBerserkDotCom')
except ImportError as e:
input(f"Error importing: {e}")
# Just realised I hadn't added this when I launched this on my laptop for the first time (fatal error)
if not os.path.exists(os.path.join(os.getcwd(), 'manga')):
os.makedirs(os.path.join(os.getcwd(),'manga'), exist_ok=True)
port = '2222' # any number you want (4 digits)
debug = True # could be True or False
host = '127.0.0.1' # could be 127.0.0.1 or 0.0.0.0 or your ip
load_dotenv()
app = Flask(__name__)
app.secret_key = os.urandom(24)
WEBHOOK_URL = os.getenv("WEBHOOK_URL")
currentPath = os.getcwd()
MANGA_DIR = os.path.join(currentPath, 'manga')
# Function to send messages to Discord
def sendToDiscord(message):
"""
Sends a message to a Discord channel using a webhook URL.
Parameters:
message (str): The message to be sent to Discord.
Returns:
None. Prints a success message if the message is sent successfully,
or an error message with the status code if the message fails to send.
"""
data = {
"content": message,
"username": "Manga Website"
}
headers = {"Content-Type": "application/json"}
response = requests.post(WEBHOOK_URL, data=json.dumps(data), headers=headers)
if response.status_code == 204:
print("Message sent to discord.")
else:
print(f"Message failed to send to discord. Status Code: {response.status_code}")
@app.route('/send_to_discord', methods=['POST'])
def send_to_discord():
"""
This function sends a message to a Discord channel using a webhook.
Parameters:
- request.json: A JSON object containing the email, subject, and body of the message.
Returns:
- A JSON response indicating whether the message was successfully sent.
- HTTP status code 400 if any required data is missing.
- HTTP status code 200 if the message is successfully sent.
- HTTP status code 500 if the message fails to send.
"""
data = request.json
email = data.get('email')
subject = data.get('subject')
body = data.get('body')
if not (email and subject and body):
return jsonify({"success": False, "error": "Missing data"}), 400
# Create the message to be sent to Discord
discord_message = {
"content": f"**New Message from:** {email}\n\n**Subject:** {subject}\n\n**Message:**\n{body}"
}
# Send the message to the Discord webhook
response = requests.post(WEBHOOK_URL, json=discord_message)
if response.status_code == 204:
return jsonify({"success": True}), 200
else:
return jsonify({"success": False, "error": "Failed to send message"}), 500
# Function to get featured manga
def get_featured_manga():
"""
This function retrieves the featured manga from the MANGA_DIR directory.
Parameters:
None
Returns:
featured_manga (list): A list of dictionaries, where each dictionary represents a manga.
Each dictionary contains the manga's id, title, description, and type.
"""
featured_manga = []
# Iterate over each folder in the MANGA_DIR
for manga_folder in os.listdir(MANGA_DIR):
manga_path = os.path.join(MANGA_DIR, manga_folder)
if os.path.isdir(manga_path):
try:
# Read the id, description, and cover image
with open(os.path.join(manga_path, 'id.txt'), 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
with open(os.path.join(manga_path, 'description.txt'), 'r', encoding='utf-8') as f:
description = f.read().strip()
with open(os.path.join(manga_path, 'type.txt'), 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
if manga_type.lower() == 'manga':
continue
# Create a dictionary with the manga data
manga_data = {
'id': manga_id,
'title': manga_folder,
'description': description,
'type': manga_type
}
featured_manga.append(manga_data)
except Exception as e:
print(f"Error reading manga data from {manga_folder}: {e}")
return featured_manga
def get_featured_manga_and_manhwa():
"""
This function retrieves the featured manga from the MANGA_DIR directory.
Parameters:
None
Returns:
featured_manga (list): A list of dictionaries, where each dictionary represents a manga.
Each dictionary contains the manga's id, title, description, and type.
"""
featured_manga = []
# Iterate over each folder in the MANGA_DIR
for manga_folder in os.listdir(MANGA_DIR):
manga_path = os.path.join(MANGA_DIR, manga_folder)
if os.path.isdir(manga_path):
try:
# Read the id, description, and cover image
with open(os.path.join(manga_path, 'id.txt'), 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
with open(os.path.join(manga_path, 'description.txt'), 'r', encoding='utf-8') as f:
description = f.read().strip()
with open(os.path.join(manga_path, 'type.txt'), 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
# Create a dictionary with the manga data
manga_data = {
'id': manga_id,
'title': manga_folder,
'description': description,
'type': manga_type
}
featured_manga.append(manga_data)
except Exception as e:
print(f"Error reading manga data from {manga_folder}: {e}")
return featured_manga
def get_featured_mangaTruncated():
"""
Retrieve a list of featured manga with truncated descriptions.
Iterates over each folder in the MANGA_DIR, reads the id, description, and type of each manga,
and appends a dictionary with the manga data to the featured_manga list.
Returns:
featured_manga (list): A list of dictionaries, each containing the id, title, description, and type of a manga.
"""
featured_manga = []
# Iterate over each folder in the MANGA_DIR
for manga_folder in os.listdir(MANGA_DIR):
manga_path = os.path.join(MANGA_DIR, manga_folder)
if os.path.isdir(manga_path):
try:
# Read the id, description, and cover image
with open(os.path.join(manga_path, 'id.txt'), 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
with open(os.path.join(manga_path, 'description.txt'), 'r', encoding='utf-8') as f:
description = f.read().strip()
with open(os.path.join(manga_path, 'type.txt'), 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
if manga_type.lower() == 'manga':
continue
if len(description) > 50:
description = description[:47] + '...'
# Create a dictionary with the manga data
manga_data = {
'id': manga_id,
'title': manga_folder,
'description': description,
'type': manga_type
}
featured_manga.append(manga_data)
except Exception as e:
print(f"Error reading manga data from {manga_folder}: {e}")
return featured_manga
def get_featured_mangaTruncatedTitle():
"""
This function retrieves a list of featured manga with truncated titles and descriptions.
Parameters:
None
Returns:
featured_manga (list): A list of dictionaries, where each dictionary represents a manga.
Each dictionary contains the manga's id, title, image title, description, and type.
"""
featured_manga = []
# Iterate over each folder in the MANGA_DIR
for manga_folder in os.listdir(MANGA_DIR):
manga_path = os.path.join(MANGA_DIR, manga_folder)
if os.path.isdir(manga_path):
try:
# Read the id, description, and cover image
with open(os.path.join(manga_path, 'id.txt'), 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
with open(os.path.join(manga_path, 'description.txt'), 'r', encoding='utf-8') as f:
description = f.read().strip()
with open(os.path.join(manga_path, 'type.txt'), 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
if manga_type.lower() == 'manga':
continue
manga_folder2 = manga_folder
if len(manga_folder) > 15:
manga_folder2 = manga_folder2[:12] + '...'
if len(description) > 50:
description = description[:47] + '...'
# Create a dictionary with the manga data
manga_data = {
'id': manga_id,
'title': manga_folder2,
'image_title': manga_folder,
'description': description,
'type': manga_type
}
featured_manga.append(manga_data)
except Exception as e:
print(f"Error reading manga data from {manga_folder}: {e}")
return featured_manga
def getAllIds():
"""
This function retrieves and prints all directory names in the MANGA_DIR.
Parameters:
None
Returns:
None. The function only prints the directory names and does not return any value.
"""
allDirs = os.listdir(MANGA_DIR)
for dir in allDirs:
print(dir)
print(MANGA_DIR)
def natural_sort_key(s):
"""Sort key that splits strings into numeric and non-numeric parts for natural sorting."""
return [int(text) if text.isdigit() else text.lower() for text in re.split('([0-9]+)', s)]
def getTBATEid():
"""
This function retrieves the id of the manga 'The Beginning After The End' from a text file.
Parameters:
None
Returns:
str: The id of the manga 'The Beginning After The End'.
The function reads the content of the file 'manga/The Beginning After The End/id.txt',
prints the content, and then returns the content.
"""
file_path = 'manga/The Beginning After The End/id.txt'
with open(file_path, 'r', encoding='utf-8') as file:
# Read the contents of the file
content = file.read()
# Print the contents
print(content)
file.close()
return content
# Route for the welcome page
@app.route("/")
def welcomePage():
"""
This function is the route for the welcome page. It retrieves the featured manga from the database
and renders the welcome page with the featured manga.
Parameters:
None
Returns:
render_template: A rendered HTML template for the welcome page with the featured manga.
"""
featured_manga = get_featured_manga_and_manhwa()
return render_template('welcome.html', featured_manga=featured_manga)
@app.route("/tbate")
def redirectToTheGoat():
"""
Redirects the user to the manga page of 'The Beginning After The End'.
Parameters:
None
Returns:
redirect: A redirect response to the manga page of 'The Beginning After The End'.
The manga page URL is constructed using the id retrieved from the function getTBATEid().
"""
tbateID = getTBATEid()
return redirect(f"/manga/{tbateID}")
@app.route("/manga/tbate")
def redirectToTheGoat2():
"""
Redirects the user to the manga page of 'The Beginning After The End'.
Parameters:
None
Returns:
redirect: A redirect response to the manga page of 'The Beginning After The End'.
The manga page URL is constructed using the id retrieved from the function getTBATEid().
"""
tbateID = getTBATEid()
return redirect(f"/manga/{tbateID}")
# Route for the home page
@app.route("/home")
def homePage():
"""
This function is the route for the home page. It retrieves the featured manga from the database
and renders the home page with the featured manga.
Parameters:
None
Returns:
render_template: A rendered HTML template for the home page with the featured manga.
The featured manga is obtained using the function `get_featured_mangaTruncated()`.
"""
featured_manga = get_featured_mangaTruncated()
return render_template('home.html', featured_manga=featured_manga)
def findAllManga():
"""
This function retrieves all manga from the MANGA_DIR directory and returns a list of manga data.
Parameters:
None
Returns:
tuple: A tuple containing two elements:
- list: A list of dictionaries, where each dictionary represents a manga and contains the manga's id, title, description, and type.
- int: The total count of manga found.
The function iterates through each folder in the MANGA_DIR directory. For each folder, it reads the id, description, and type from the respective files.
It then creates a dictionary with the manga's data and appends it to the manga_list. Finally, it returns the manga_list and the manga_count.
"""
manga_list = []
manga_count = 0
for manga_folder in os.listdir(MANGA_DIR):
print(manga_folder)
manga_path = os.path.join(MANGA_DIR, manga_folder)
if os.path.isdir(manga_path):
try:
# Read the id, description, and cover image
with open(os.path.join(manga_path, 'id.txt'), 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
with open(os.path.join(manga_path, 'description.txt'), 'r', encoding='utf-8') as f:
description = f.read().strip()
with open(os.path.join(manga_path, 'type.txt'), 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
if manga_type.lower() == 'manga':
continue
manga_count += 1 # Increment the manga count
if len(description) > 50:
description = description[:47] + '...'
# Create a dictionary with the manga data
manga_data = {
'id': manga_id,
'title': manga_folder,
'description': description,
'type': manga_type
}
manga_list.append(manga_data)
except Exception as e:
print(f"Error reading manga data from {manga_folder}: {e}")
return manga_list, manga_count
@app.route("/manga")
def manga_list():
"""
This function retrieves all manga from the MANGA_DIR directory and returns a list of manga data.
Parameters:
None
Returns:
tuple: A tuple containing two elements:
- list: A list of dictionaries, where each dictionary represents a manga and contains the manga's id, title, description, and type.
- int: The total count of manga found.
The function iterates through each folder in the MANGA_DIR directory. For each folder, it reads the id, description, and type from the respective files.
It then creates a dictionary with the manga's data and appends it to the manga_list. Finally, it returns the manga_list and the manga_count.
"""
mangaList, mangaCount = findAllManga()
return render_template('manga.html', manga=mangaList, manga_count=mangaCount)
@app.route("/search")
def search():
"""
This function handles the search functionality of the web application.
It renders the searchManga.html template, which allows users to search for manga.
Parameters:
None
Returns:
render_template: A rendered HTML template for the search page.
"""
return render_template("searchManga.html")
@app.route('/contact')
def contact():
"""
This function handles the contact page of the web application.
It renders the 'contact.html' template, which displays the contact form and other relevant information.
Parameters:
None
Returns:
render_template: A rendered HTML template for the contact page.
"""
return render_template('contact.html')
def get_chapters_for_manga(manga_title):
"""
Retrieves a list of chapters for a given manga.
Parameters:
manga_title (str): The title of the manga for which to retrieve chapters.
Returns:
list: A list of dictionaries, where each dictionary represents a chapter.
Each dictionary contains a 'title' key with the chapter's title.
The chapters are sorted numerically if they follow a pattern like "Chapter 1", "Chapter 2", etc.
"""
chapters = []
chapters_path = os.path.join(MANGA_DIR, manga_title, 'Chapters')
if os.path.isdir(chapters_path):
for chapter_name in os.listdir(chapters_path):
chapter_path = os.path.join(chapters_path, chapter_name)
if os.path.isdir(chapter_path):
chapters.append({'title': chapter_name})
# Sort chapters numerically if they follow a pattern like "Chapter 1", "Chapter 2", etc.
chapters.sort(key=lambda x: int(re.findall(r'\d+', x['title'])[0]) if re.findall(r'\d+', x['title']) else 0)
return chapters
@app.route("/manga/<int:manga_id>")
def manga_detail(manga_id):
"""
This function retrieves the details of a specific manga based on its ID.
It retrieves the featured manga and recommended manga, then finds the manga with the given ID.
If the manga is found, it retrieves the chapters for the manga and renders the 'manga_detail.html' template.
If the manga is not found, it returns a 404 status code.
Parameters:
manga_id (int): The ID of the manga to retrieve details for.
Returns:
render_template: If the manga is found, it renders the 'manga_detail.html' template with the manga details, chapters, and recommended manga.
If the manga is not found, it returns a 404 status code.
"""
featured_manga = get_featured_manga()
reccomended_manga = get_featured_mangaTruncatedTitle() # Correct variable name
manga = next((m for m in featured_manga if m['id'] == str(manga_id)), None)
if manga:
chapters = get_chapters_for_manga(manga['title'])
chapters.reverse()
return render_template('manga_detail.html',
mangaId = manga_id,
manga=manga,
chapters=chapters,
reccomended_manga=reccomended_manga # Use the correct variable name
)
else:
return 404
def buildURLFromID(search_id):
"""
This function constructs a URL for a manga based on its ID.
Parameters:
search_id (str): The ID of the manga to search for.
Returns:
str: The constructed URL for the manga. If the file with the correct ID is not found, it returns None.
"""
base_directory = 'manga/'
# Walk through the directory tree
for root, dirs, files in os.walk(base_directory):
# Check if 'id.txt' file is in the current directory
if 'id.txt' in files:
# Construct the path to the 'id.txt' file
file_path = os.path.join(root, 'id.txt')
# Read the contents of the file
with open(file_path, 'r', encoding='utf-8') as file:
file_id = file.read().strip() # Read and strip any extra whitespace
file_path = file_path[:-7]
# Check if the ID in the file matches the search_id
if file_id == search_id:
manga_name = file_path.lower()
manga_name = manga_name.replace(' ', '-')
print(manga_name)
# Construct the URL (you can adjust this format as needed)
url = f'https://www.mangaread.org/{manga_name}'
return url
# Return None if the file with the correct ID is not found
return None
@app.route('/updateManhwa', methods=['POST'])
def updateManhwaFunction():
mangaID = request.json.get('mangaId')
print(f"Manga ID recieved: {mangaID}")
url = buildURLFromID(search_id=str(mangaID))
print(f"URL created: {url}")
WebScrapers.OnSite.mangaReaderDotOrg.main(url=url)
return f"Updated {url}", 200
@app.route("/manga_reader")
def manga_reader_home():
"""
This function retrieves a list of manga folders from the MANGA_DIR directory and prepares a list of manga data for the manga reader home page.
Parameters:
None
Returns:
render_template: A rendered HTML template for the manga reader home page, containing a list of manga data. The manga data includes the manga name, ID, and link.
The function iterates through the manga folders in the MANGA_DIR directory. For each manga folder, it checks if the 'type.txt' file exists and if its content is "Manga".
If the conditions are met, it appends a tuple containing the manga name, ID, and link to the manga_list. If the manga name is longer than 80 characters, it truncates it to 77 characters and appends an ellipsis.
Finally, it returns the rendered HTML template for the manga reader home page with the manga_list.
"""
manga_folders = [folder for folder in os.listdir(MANGA_DIR) if os.path.isdir(os.path.join(MANGA_DIR, folder))]
manga_list = []
for manga in manga_folders:
mangaLink = manga
manga_type_path = os.path.join(MANGA_DIR, manga, 'type.txt')
manga_description_path = os.path.join(MANGA_DIR, manga, 'description.txt')
if os.path.isfile(manga_type_path):
with open(manga_type_path, 'r', encoding='utf-8') as f:
manga_type = f.read().strip()
if manga_type == "Manga":
if os.path.isfile(manga_description_path):
with open(manga_description_path, 'r', encoding='utf-8') as f:
manga_description = f.read().strip()
if len(manga_description) > 424:
manga_description = manga_description[:397]
manga_description += "..."
manga_list.append((manga, manga_type, mangaLink, manga_description))
total_manga = len(manga_list)
return render_template('manga_reader_home.html', manga_list=manga_list, numOfManga=total_manga)
def berserk_sort_key(chapter_name):
# Define your custom sorting logic here
# Example: Extract numbers from chapter names to sort numerically
numbers = re.findall(r'\d+', chapter_name)
return int(numbers[0]) if numbers else float('inf')
@app.route("/manga_reader/<manga_name>")
def manga_details(manga_name):
"""
This function retrieves the details of a specific manga based on its name.
It retrieves the cover image, description, and a list of chapters for the manga.
"""
manga_name = urllib.parse.unquote(manga_name)
manga_path = os.path.join(MANGA_DIR, manga_name)
if not os.path.isdir(manga_path):
return "Manga not found", 404
# Read manga cover image
cover_image = None
for ext in ['jpg', 'jpeg', 'png', 'gif', 'webp']:
potential_cover = os.path.join(manga_path, f'cover_image.{ext}')
if os.path.isfile(potential_cover):
cover_image = url_for('static', filename=os.path.relpath(potential_cover, 'static'))
break
# Read description
description_path = os.path.join(manga_path, 'description.txt')
if os.path.isfile(description_path):
with open(description_path, 'r', encoding='utf-8') as f:
description = f.read().strip()
else:
description = "No description available."
# Read manga ID
id_path = os.path.join(manga_path, 'id.txt')
if os.path.isfile(id_path):
with open(id_path, 'r', encoding='utf-8') as f:
manga_id = f.read().strip()
else:
manga_id = "ID not found."
# List chapters
chapters_dir = os.path.join(manga_path, "Chapters")
chapters = [folder for folder in os.listdir(chapters_dir) if os.path.isdir(os.path.join(chapters_dir, folder))]
if manga_name == "Berserk":
chapters.sort(key=berserk_sort_key) # Custom sort function
else:
chapters.sort(key=natural_sort_key)
chapters = chapters[::-1]
# Generate URLs for chapter thumbnails
images = [
url_for('serve_thumbnail_chapter', manga_title=manga_name, chapterName=chapter)
for chapter in chapters
]
return render_template('manga_details.html', manga_name=manga_name, cover_image=cover_image, description=description, chapters=chapters, manga_id=manga_id, images=images)
@app.route('/manga_reader/<manga_name>/<chapter_name>')
def manga_reader(manga_name, chapter_name):
"""
This function handles the display of a specific chapter in the manga reader.
It retrieves the list of images in the chapter directory, sorts them naturally,
and retrieves the list of chapters for the manga. It also determines the next
and previous chapters.
Parameters:
manga_name (str): The name of the manga.
chapter_name (str): The name of the chapter.
Returns:
render_template: A rendered HTML template for the manga reader, containing
the images, chapter name, manga name, next chapter, previous chapter,
and the saved height from the session. If the chapter directory
does not exist, it returns a 404 status code with the message "Chapter not found".
"""
manga_name = urllib.parse.unquote(manga_name)
chapter_name = urllib.parse.unquote(chapter_name)
chapter_path = os.path.join(MANGA_DIR, manga_name, "Chapters", chapter_name)
if not os.path.isdir(chapter_path):
return "Chapter not found", 404
images = sorted([img for img in os.listdir(chapter_path) if img.lower().endswith(('jpg', 'jpeg', 'png', 'gif', 'webp'))])
images = [url_for('manga_reader_image', manga_name=manga_name, chapter_name=chapter_name, filename=img) for img in images]
images.sort(key=natural_sort_key)
# Retrieve the list of chapters
chapters_path = os.path.join(MANGA_DIR, manga_name, "Chapters")
chapters = sorted(os.listdir(chapters_path), key=natural_sort_key)
# Find the current chapter index
current_chapter_index = chapters.index(chapter_name)
# Determine next and previous chapters
next_chapter = chapters[current_chapter_index + 1] if current_chapter_index < len(chapters) - 1 else None
previous_chapter = chapters[current_chapter_index - 1] if current_chapter_index > 0 else None
# Get the saved height from session
saved_height = session.get('mangaPanelHeight', 600)
return render_template('manga_reader.html', images=images, chapter_name=chapter_name, manga_name=manga_name,
next_chapter=next_chapter, previous_chapter=previous_chapter, saved_height=saved_height)
@app.route('/update')
def update():
return render_template('update.html')
@app.route('/update/<id>', methods=['POST'])
def update_id(id):
print(f"Received ID from URL: {id}")
WebScrapers.OnSite.UPDATE.main(str(id))
return jsonify({"id": id})
@app.route('/scrape')
def scrapers():
return render_template('scrapers.html')
@app.route('/scrape/mangaReaderOrg')
def scrapemangaReaderOrg():
return render_template('scrapemangaReaderOrg.html')
@app.route('/scrape/manhwaClanCom')
def scrapemanhwaClanCom():
return render_template('scrapemanhwaClanCom.html')
@app.route('/scrape/Berserk')
def scrapeBerserkPage():
return render_template('scrapeBerserk.html')
@app.route('/real/scrape/berserk', methods=['POST'])
def scrape_berserk():
try:
print(f"Scraping Berserk")
WebScrapers.OnSite.readBerserkDotCom.main()
return jsonify({"status": "success"})
except Exception as e:
print(f"Error scraping mangaReaderOrg: {e}")
return jsonify({"status": "error", "error": str(e)})
@app.route('/real/scrape/mangaReaderOrg', methods=['POST'])
def scrape_mangaReaderOrg():
data = request.get_json()
if data and 'link' in data:
try:
link = data['link']
print(f"Starting Scraping mangaReaderOrg")
WebScrapers.OnSite.mangaReaderDotOrg.main(link)
return jsonify({"status": "success"})
except Exception as e:
print(f"Error scraping mangaReaderOrg: {e}")
return jsonify({"status": "error", "error": str(e)})
else:
print("data not recieved /real/scrape/mangaReaderOrg")
return jsonify({"status": "error", "error": str(e)})
@app.route('/real/scrape/manhwaClanDotCom', methods=['POST'])
def scrape_manhwaClanDotCom():
data = request.get_json()
if data and 'link' in data:
try:
link = data['link']
print(f"Starting Scraping manhwaClanDotCom")
WebScrapers.OnSite.manhwaClanDotCom.main(link)
return jsonify({"status": "success"})
except Exception as e:
print(f"Error scraping manhwaClanDotCom: {e}")
return jsonify({"status": "error", "error": str(e)})
else:
print("data not recieved /real/scrape/manhwaClanDotCom")
return jsonify({"status": "error", "error": str(e)})
@app.route('/save_height', methods=['POST'])
def save_height():
"""
This function handles the POST request to save the height of the manga panel.
It retrieves the height from the request JSON data, saves it in the session,
and returns a JSON response with a status of "success".
Parameters:
None
Returns:
jsonify: A JSON response with a status of "success".
"""
height = request.json.get('height')
session['mangaPanelHeight'] = height
return jsonify({"status": "success"})
@app.route('/manga_reader_image/<manga_name>/<chapter_name>/<filename>')
def manga_reader_image(manga_name, chapter_name, filename):
"""
Serves an image file for a specific manga chapter.
Parameters:
manga_name (str): The name of the manga.
chapter_name (str): The name of the chapter.
filename (str): The name of the image file.
Returns:
send_from_directory: A response that sends the image file from the specified directory.
If the file does not exist, it returns a 404 status code.
"""
manga_name = urllib.parse.unquote(manga_name)
chapter_name = urllib.parse.unquote(chapter_name)
chapter_name = replace_special_characters(chapter_name)
directory = os.path.join(MANGA_DIR, manga_name, "Chapters", chapter_name)
file_path = os.path.join(directory, filename)
if not os.path.isfile(file_path):
abort(404)
return send_from_directory(directory, filename)
@app.route('/manga/<manga_title>/chapter/<chapterName>')
def chapter_detail(manga_title, chapterName):
"""
This function retrieves and displays the images for a specific chapter in a manga.
It also retrieves the next and previous chapters for navigation.
Parameters:
manga_title (str): The title of the manga.
chapterName (str): The name of the chapter.
Returns:
render_template: A response that renders the 'manhwaContent.html' template with the images, manga title, chapter name, next chapter, and previous chapter.
If the chapter directory does not exist, it returns a 404 status code with the message "Chapter not found".
"""
chapter_dir = os.path.join(MANGA_DIR, manga_title, 'Chapters', chapterName)
try:
# Get all images in the chapter directory
images = [f for f in os.listdir(chapter_dir) if os.path.isfile(os.path.join(chapter_dir, f)) and re.match(r'.*\.(jpg|jpeg|gif|webp|png)$', f, re.IGNORECASE)]
# Get the manhwa id for the link in the page
manhwaID = None
manhwaPath = os.path.join(MANGA_DIR, manga_title)
print(manhwaPath)
if os.path.isdir(manhwaPath):
id_path = os.path.join(manhwaPath, 'id.txt')
print(id_path)
try:
with open(id_path, 'r') as f:
manhwaID = f.read()
f.close()
except FileNotFoundError as e:
input(e)
# Sort images naturally
images.sort(key=natural_sort_key) # Using natsorted for natural sorting
# Get and sort chapters for the manga