Skip to content

Commit ce847be

Browse files
authored
Initial Commit
1 parent 4a53b4b commit ce847be

File tree

1 file changed

+283
-0
lines changed

1 file changed

+283
-0
lines changed

WebtoonReader.py

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
# Makes sure modules are installed
2+
try:
3+
import tkinter as tk
4+
from tkinter import filedialog
5+
from PIL import ImageTk, Image
6+
except ModuleNotFoundError:
7+
print("Downloading packages...")
8+
os.system('pip install tkinter')
9+
os.system('pip install pillow')
10+
print("Please run the program again.")
11+
12+
13+
import os, json, re
14+
from CustomScroller import ImageScroller
15+
16+
SETTINGS_FILE = os.path.join(os.getcwd(), "webtoonreader_settings.json")
17+
18+
# To do
19+
# Add bookmarks of where you left off on a manga
20+
21+
class WebtoonReader:
22+
def __init__(self):
23+
# Create settings file in the home directory if it does not exist
24+
if not os.path.isfile(SETTINGS_FILE):
25+
with open(SETTINGS_FILE, "a") as f:
26+
json.dump({"library" : os.getcwd(), "width" : 720, "height" : 800, "scroll_speed" : 3, "recent_chapter" : "", "recent_chapter_index" : ""}, f)
27+
f.close()
28+
29+
30+
# Window
31+
self.window = tk.Tk()
32+
self.window.resizable(False, False)
33+
34+
self.width = get_json('width')
35+
self.height = get_json('height')
36+
self.scroll_speed = get_json('scroll_speed')
37+
38+
39+
# Center Window
40+
x = int(self.window.winfo_screenwidth()/2 - self.width/2)
41+
y = int(self.window.winfo_screenheight()/2 - self.height/2)
42+
self.window.geometry("+{}+{}".format(x, y))
43+
44+
# ImageScroller
45+
chapter_path = get_json('recent_chapter')
46+
self.frame = ImageScroller(self.window, path=chapter_path, scrollbarwidth=15, width=self.width, height=self.height, speed=self.scroll_speed)
47+
self.frame.pack()
48+
manga = os.path.basename(os.path.dirname(chapter_path))
49+
self.window.title("[WebtoonReader] - " + manga + ": " + os.path.basename(chapter_path))
50+
51+
# Menubar
52+
menubar = tk.Menu(self.window)
53+
settingsmenu = tk.Menu(menubar, tearoff=0)
54+
settingsmenu.add_command(label="Load Library", command=self.get_library)
55+
settingsmenu.add_command(label="Load Manga", command=self.load_manga)
56+
settingsmenu.add_command(label="Load Chapter", command=lambda: self.create_chapter(None))
57+
settingsmenu.add_command(label="Settings", command=self.set_settings)
58+
settingsmenu.add_command(label="Help")
59+
60+
menubar.add_cascade(label="Settings", menu=settingsmenu)
61+
menubar.add_cascade(label="Previous Chapter", command=self.prev_chapter)
62+
menubar.add_cascade(label="Next Chapter", command=self.next_chapter)
63+
64+
# Keybind shortcuts
65+
self.window.bind("<Left>", self.key_prev_chapter)
66+
self.window.bind("<a>", self.key_prev_chapter)
67+
self.window.bind("<Right>", self.key_next_chapter)
68+
self.window.bind("<d>", self.key_next_chapter)
69+
70+
71+
# Start the window
72+
self.window.config(menu=menubar)
73+
self.window.mainloop()
74+
75+
76+
# Loads the directory containing all mangas
77+
def get_library(self):
78+
library_path = tk.filedialog.askdirectory()
79+
80+
if library_path != "":
81+
update_json('library', library_path)
82+
83+
84+
# Loads a manga from where the user last left off
85+
def load_manga(self):
86+
manga_path = tk.filedialog.askdirectory()
87+
88+
if manga_path == "":
89+
return
90+
91+
chapter_path = get_json(os.path.basename(manga_path))
92+
self.create_chapter(chapter_path)
93+
94+
95+
# Loads a chapter to read
96+
def create_chapter(self, path):
97+
if path != None:
98+
chapter_path = path
99+
else:
100+
chapter_path = tk.filedialog.askdirectory()
101+
if chapter_path == "":
102+
return
103+
104+
105+
manga_path = os.path.dirname(chapter_path)
106+
chapter_list = abslistdir(manga_path)
107+
chapter_index = -1
108+
109+
# Finds the index of the current manga in the directory
110+
for index, chapter in enumerate(chapter_list):
111+
if chapter == chapter_path:
112+
chapter_index = index
113+
break
114+
115+
# Updates the image scroller
116+
self.frame.destroy()
117+
self.frame = ImageScroller(self.window, path=chapter_path, scrollbarwidth=15, width=self.width, height=self.height, speed=self.scroll_speed)
118+
self.frame.pack()
119+
120+
# Updates settings json
121+
update_json('recent_chapter', chapter_path)
122+
update_json('recent_chapter_index', chapter_index)
123+
manga = os.path.basename(manga_path)
124+
update_json(manga, chapter_path)
125+
self.window.title("[WebtoonReader] - " + manga + ": " + os.path.basename(chapter_path))
126+
127+
128+
# Finds the next chapter of the manga
129+
def next_chapter(self):
130+
chapter_index = get_json('recent_chapter_index')
131+
chapter_index += 1
132+
133+
# Checks if the current chapter is the last chapter
134+
chapter_path = get_json('recent_chapter')
135+
manga_path = os.path.dirname(chapter_path)
136+
chapter_list = abslistdir(manga_path)
137+
138+
# Checks if it is the last chapter
139+
if chapter_index >= len(chapter_list):
140+
tk.messagebox.showwarning('Warning', 'Last Chapter')
141+
return
142+
143+
chapter_path = chapter_list[chapter_index]
144+
145+
# Updates the image scroller
146+
self.frame.destroy()
147+
self.frame = ImageScroller(self.window, path=chapter_path, scrollbarwidth=15, width=self.width, height=self.height, speed=self.scroll_speed)
148+
self.frame.pack()
149+
150+
# Updates the settings json
151+
update_json('recent_chapter', chapter_path)
152+
update_json('recent_chapter_index', chapter_index)
153+
manga = os.path.basename(manga_path)
154+
update_json(manga, chapter_path)
155+
self.window.title("[WebtoonReader] - " + manga + ": " + os.path.basename(chapter_path))
156+
157+
158+
# Finds the previous chapter of the manga
159+
def prev_chapter(self):
160+
chapter_index = get_json('recent_chapter_index')
161+
chapter_index -= 1
162+
163+
# Checks if the current chapter is the first
164+
chapter_path = get_json('recent_chapter')
165+
manga_path = os.path.dirname(chapter_path)
166+
chapter_list = abslistdir(manga_path)
167+
168+
# Checks if it is the first chapter
169+
if chapter_index == -1:
170+
tk.messagebox.showwarning('Warning', 'First Chapter')
171+
return
172+
173+
chapter_path = chapter_list[chapter_index]
174+
175+
# Updates the image scroller
176+
self.frame.destroy()
177+
self.frame = ImageScroller(self.window, path=chapter_path, scrollbarwidth=15, width=self.width, height=self.height, speed=self.scroll_speed)
178+
self.frame.pack()
179+
180+
# Updates the settings json
181+
update_json('recent_chapter', chapter_path)
182+
update_json('recent_chapter_index', chapter_index)
183+
manga = os.path.basename(manga_path)
184+
update_json(manga, chapter_path)
185+
self.window.title("[WebtoonReader] - " + manga + ": " + os.path.basename(chapter_path))
186+
187+
188+
# Keybind shortcut for next chapter
189+
def key_next_chapter(self, e):
190+
self.next_chapter()
191+
192+
193+
# Keybind shortcut for previous chapter
194+
def key_prev_chapter(self, e):
195+
self.prev_chapter()
196+
197+
198+
# Settings window
199+
def set_settings(self):
200+
settings = tk.Toplevel()
201+
x = int(self.window.winfo_screenwidth()/2 - 200)
202+
y = int(self.window.winfo_screenheight()/2 - 200)
203+
settings.geometry("%dx%d+%d+%d" % (400, 400, x, y))
204+
205+
width_label = tk.Label(settings, text="Width").pack(pady=10)
206+
self.width_slider = tk.Scale(settings, from_=200, to=self.window.winfo_screenwidth(), orient=tk.HORIZONTAL, length=300, resolution=20)
207+
self.width_slider.set(self.width)
208+
self.width_slider.pack(pady=10)
209+
self.width_slider.bind("<ButtonRelease-1>", self.update_width)
210+
211+
height_label = tk.Label(settings, text="Height").pack(pady=10)
212+
self.height_slider = tk.Scale(settings, from_=200, to=self.window.winfo_screenheight(), orient=tk.HORIZONTAL, length=250, resolution=20)
213+
self.height_slider.set(self.height)
214+
self.height_slider.pack(pady=10)
215+
self.height_slider.bind("<ButtonRelease-1>", self.update_height)
216+
217+
speed_label = tk.Label(settings, text="Scroll Speed").pack(pady=10)
218+
self.scroll_speed_slider = tk.Scale(settings, from_=1, to=5, orient=tk.HORIZONTAL)
219+
self.scroll_speed_slider.set(self.scroll_speed)
220+
self.scroll_speed_slider.pack(pady=10)
221+
self.scroll_speed_slider.bind("<ButtonRelease-1>", self.update_speed)
222+
223+
settings.mainloop()
224+
225+
# Updates width in settings json
226+
def update_width(self, e):
227+
self.width = self.width_slider.get()
228+
update_json('width', self.width_slider.get())
229+
230+
# Updates height in settings json
231+
def update_height(self, e):
232+
self.height = self.height_slider.get()
233+
update_json('height', self.height_slider.get())
234+
235+
# Updates scroll speed in settings json
236+
def update_speed(self, e):
237+
self.scroll_speed = self.scroll_speed_slider.get()
238+
update_json('scroll_speed', self.scroll_speed_slider.get())
239+
240+
241+
# Update the json value if key exists, otherwise adds to json
242+
def update_json(key, value):
243+
json_file = open(SETTINGS_FILE, "r")
244+
data = json.load(json_file)
245+
data[key] = value
246+
247+
json_file = open(SETTINGS_FILE, "w")
248+
json_file.write(json.dumps(data))
249+
json_file.close()
250+
251+
252+
# Get json value (with key)
253+
def get_json(key):
254+
json_file = open(SETTINGS_FILE, "r")
255+
data = json.load(json_file)
256+
for item in data:
257+
if key in item:
258+
value = data[key]
259+
json_file.close()
260+
return value
261+
json_file.close()
262+
return None
263+
264+
265+
# Returns a natural sorted list of absolute paths directories
266+
def abslistdir(path):
267+
list = []
268+
for root, dirs, files in os.walk(path):
269+
for dir in dirs:
270+
list.append(os.path.join(root, dir).replace("\\", "/"))
271+
list.sort(key=natural_sort_key)
272+
return list
273+
274+
275+
# Natural sort a list
276+
def natural_sort_key(list):
277+
return [int(text) if text.isdigit() else text.lower()
278+
for text in re.split(re.compile('([0-9]+)'), list)]
279+
280+
281+
# Main
282+
if __name__ == "__main__":
283+
WebtoonReader()

0 commit comments

Comments
 (0)