-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmovie_database.py
More file actions
344 lines (286 loc) · 17.5 KB
/
Copy pathmovie_database.py
File metadata and controls
344 lines (286 loc) · 17.5 KB
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
import tkinter as tk
from tkinter import ttk, simpledialog, messagebox
from tkcalendar import DateEntry
import pickle
import os
import random
import time
USER_CREDENTIALS = [
('SysAdmin', '1234'),
]
class Product:
def __init__(self, barcode, name, shelf_num, notes, physical_media):
self.barcode = barcode
self.name = name
self.shelf_num = shelf_num
self.notes = notes
self.physical_media = physical_media # New attribute
self.is_taken_out = False
self.last_watched = "N/A"
class LoginWindow:
successful = False
def __init__(self, parent):
self.appdata_path = os.path.join(os.getenv('APPDATA'), 'MovieDB')
self.root = tk.Toplevel(parent)
self.root.title("Login")
ttk.Label(self.root, text="Barcode:").grid(row=0, column=0, padx=10, pady=10)
self.username_entry = ttk.Entry(self.root)
self.username_entry.grid(row=0, column=1, padx=10, pady=10)
ttk.Label(self.root, text="Passcode:").grid(row=1, column=0, padx=10, pady=10)
self.password_entry = ttk.Entry(self.root, show="*")
self.password_entry.grid(row=1, column=1, padx=10, pady=10)
self.login_button = ttk.Button(self.root, text="Login", command=self.verify_credentials)
self.login_button.grid(row=3, column=0, columnspan=2, pady=10)
self.parent = parent
def verify_credentials(self):
username = self.username_entry.get()
pass_number = self.password_entry.get()
if (username, pass_number) in USER_CREDENTIALS:
time.sleep(2)
if(self.successful == False):
self.root.destroy()
self.parent.deiconify()
return
else:
messagebox.showerror("Login failed", "User secret not found")
else:
messagebox.showerror("Login failed", "Invalid username or pass-number")
class BarcodeApp:
def __init__(self, root):
self.root = root
self.root.title("Movie Database App")
self.version_code = 'v1.3.4'
self.appdata_path = os.path.join(os.getenv('APPDATA'), 'MovieDB')
self.products = []
# Entry for barcode
ttk.Label(root, text="Barcode:").grid(row=0, column=0, padx=10, pady=10)
self.barcode_entry = ttk.Entry(root)
self.barcode_entry.grid(row=0, column=1, padx=10, pady=10)
# Entry for product name
ttk.Label(root, text="Product Name:").grid(row=1, column=0, padx=10, pady=10)
self.product_entry = ttk.Entry(root)
self.product_entry.grid(row=1, column=1, padx=10, pady=10)
# Entry for shelf numbers
ttk.Label(root, text="Shelf Number:").grid(row=2, column=0, padx=10, pady=10)
self.shelf_num_entry = ttk.Entry(root)
self.shelf_num_entry.grid(row=2, column=1, padx=10, pady=10)
# Entry for notes
ttk.Label(root, text="Notes:").grid(row=3, column=0, padx=10, pady=10)
self.notes_entry = ttk.Entry(root)
self.notes_entry.grid(row=3, column=1, padx=10, pady=10)
# Entry for type of physical media
ttk.Label(root, text="Type of Physical Media:").grid(row=4, column=0, padx=10, pady=10)
self.physical_media_entry = ttk.Entry(root)
self.physical_media_entry.grid(row=4, column=1, padx=10, pady=10)
# Save button
self.save_button = ttk.Button(root, text="Save", command=self.save_product)
self.save_button.grid(row=4, column=0, columnspan=2, pady=10)
#Random Button
self.random_movie_button = ttk.Button(root, text="Pick Random Movie", command=self.show_random_movie)
self.random_movie_button.grid(row=11, column=0, columnspan=2, pady=10)
# New button to count all products
self.count_button = ttk.Button(root, text="Count All The Physical Media", command=self.count_all_products) # New line for count button
self.count_button.grid(row=10, column=0, columnspan=2, pady=10) # New line to position the button
# Button to display duplicate product names
self.duplicate_display_button = ttk.Button(root, text="Display Duplicate Products", command=self.display_duplicate_products)
self.duplicate_display_button.grid(row=12, column=0, columnspan=2, pady=10)
# Export Titles button
self.export_button = ttk.Button(root, text="Export Titles to .txt", command=self.export_titles_to_txt)
self.export_button.grid(row=13, column=0, columnspan=2, pady=10)
ttk.Label(root, text=self.version_code).grid(row=13, column=2, padx=10, pady=10)
# List of products
self.product_frame = ttk.Frame(root) # New frame to hold Treeview and Scrollbar
self.product_frame.grid(row=5, column=0, columnspan=2, padx=10, pady=10)
self.product_list = ttk.Treeview(self.product_frame, columns=("Barcode", "Product", "Shelf", "Is Taken Out", "Last Watched", "Notes", "Type of Media"))
self.product_list.pack(side=tk.LEFT, fill=tk.BOTH) # Changed this line to use pack()
# Scrollbar for the Treeview
self.scrollbar = ttk.Scrollbar(self.product_frame, orient="vertical", command=self.product_list.yview) # New Scrollbar
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # New line to pack scrollbar
self.product_list.config(yscrollcommand=self.scrollbar.set) # New line to connect scrollbar to Treeview
self.product_list.heading("Barcode", text="Barcode")
self.product_list.heading("Product", text="Product Name")
self.product_list.heading("Shelf", text="Shelf Number")
self.product_list.heading("Is Taken Out", text="Is Taken Out")
self.product_list.heading("Last Watched", text="Last Watched")
self.product_list.heading("Notes", text="Notes")
self.product_list.heading("Type of Media", text="Type of Physical Media")
self.product_list.bind("<Double-1>", self.toggle_taken_out)
# Right-click context menu
self.context_menu = tk.Menu(root, tearoff=0)
self.context_menu.add_command(label="Mark date taken out", command=self.mark_taken_out_date)
self.context_menu.add_command(label="Edit Title", command=self.edit_product_name)
self.context_menu.add_command(label="Edit Shelf Number", command=self.edit_shelf_number)
self.context_menu.add_command(label="Edit Notes", command=self.edit_notes)
self.context_menu.add_command(label="Delete Product", command=self.delete_product)
self.context_menu.add_command(label="Sort by Shelf Number", command=self.sort_by_shelf_number)
self.product_list.bind("<Button-3>", self.show_context_menu)
# Search entries and buttons
self.search_by_barcode_entry = ttk.Entry(root)
self.search_by_barcode_entry.grid(row=6, column=0, padx=10, pady=10)
ttk.Button(root, text="Search by Barcode", command=lambda: self.search_product('barcode')).grid(row=6, column=1, pady=10)
self.search_by_name_entry = ttk.Entry(root)
self.search_by_name_entry.grid(row=7, column=0, padx=10, pady=10)
ttk.Button(root, text="Search by Name", command=lambda: self.search_product('name')).grid(row=7, column=1, pady=10)
self.search_by_shelf_num_entry = ttk.Entry(root)
self.search_by_shelf_num_entry.grid(row=8, column=0, padx=10, pady=10)
ttk.Button(root, text="Search by Shelf Number", command=self.search_by_shelf_number).grid(row=8, column=1, pady=10)
# Return button to show all products after searching
ttk.Button(root, text="Return to All", command=self.display_all_products).grid(row=9, column=0, columnspan=2, pady=10)
# Load products from file on startup
self.load_products()
# Bind the close event to save products to a file
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
def save_product(self):
barcode = self.barcode_entry.get().strip()
product_name = self.product_entry.get().strip()
shelf_num = self.shelf_num_entry.get().strip()
physical_media = self.physical_media_entry.get().strip() # Get the value from the entry
notes = self.notes_entry.get().strip()
if not shelf_num.isdigit():
messagebox.showerror("Error", "Shelf Number must be a numeric value!")
return
if barcode and product_name and shelf_num and physical_media:
if not notes:
""
new_product = Product(barcode, product_name, int(shelf_num), notes, physical_media)
self.products.append(new_product)
self.product_list.insert("", "end", values=(new_product.barcode, new_product.name, new_product.shelf_num, new_product.is_taken_out, new_product.last_watched, new_product.notes, new_product.physical_media))
self.save_products()
self.barcode_entry.delete(0,tk.END)
self.product_entry.delete(0,tk.END)
self.shelf_num_entry.delete(0,tk.END)
self.notes_entry.delete(0,tk.END)
self.physical_media_entry.delete(0,tk.END)
else:
messagebox.showerror("Error", "All fields are required!")
def toggle_taken_out(self, event):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
product.is_taken_out = not product.is_taken_out
self.product_list.item(selected_item, values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
self.save_products()
def mark_taken_out_date(self):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
date_taken_out = simpledialog.askstring("Input", "Enter date taken out (YYYY-MM-DD):", parent=self.root)
if date_taken_out:
product.last_watched = date_taken_out
self.product_list.item(selected_item, values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
self.save_products()
def show_random_movie(self):
if not self.products:
messagebox.showinfo("Random Movie Picker", "No movies in the database!")
return
random_product = random.choice(self.products)
# Optionally, display the random product's details in a message box or update the GUI to focus on this item
messagebox.showinfo("Random Movie Picker", f"Random Movie: {random_product.name}\nShelf Number: {random_product.shelf_num}\nType of Media: {random_product.physical_media}\nNotes: {random_product.notes}")
def delete_product(self):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
self.products.remove(product)
self.product_list.delete(selected_item)
self.save_products()
def edit_shelf_number(self):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
new_shelf_num = simpledialog.askstring("Input", "Enter new Shelf Number:", parent=self.root)
if new_shelf_num and new_shelf_num.isdigit():
product.shelf_num = int(new_shelf_num)
self.product_list.item(selected_item, values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
self.save_products()
def edit_product_name(self):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
new_product_name = simpledialog.askstring("Input", "Enter new Product Name:", parent=self.root)
if new_product_name:
product.name = new_product_name
self.product_list.item(selected_item, values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
self.save_products()
def edit_notes(self):
selected_item = self.product_list.selection()[0]
product = next((p for p in self.products if p.barcode == self.product_list.item(selected_item, "values")[0]), None)
if product:
new_notes = simpledialog.askstring("Input", "Enter new Notes:", parent=self.root)
if new_notes:
product.notes = new_notes
self.product_list.item(selected_item, values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
self.save_products()
def show_context_menu(self, event):
self.context_menu.post(event.x_root, event.y_root)
def search_by_shelf_number(self):
query = self.search_by_shelf_num_entry.get().strip()
if not query.isdigit():
messagebox.showerror("Error", "Please enter a numeric value for shelf number!")
return
query = int(query)
self.product_list.delete(*self.product_list.get_children())
for product in self.products:
if product.shelf_num == query:
self.product_list.insert("", "end", values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
def search_product(self, key):
query = self.search_by_barcode_entry.get().strip() if key == 'barcode' else self.search_by_name_entry.get().strip()
if not query:
return
self.product_list.delete(*self.product_list.get_children())
for product in self.products:
if query.lower() in getattr(product, key).lower():
self.product_list.insert("", "end", values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
# Clear the search entries
self.search_by_barcode_entry.delete(0, tk.END)
self.search_by_name_entry.delete(0, tk.END)
def display_all_products(self):
self.product_list.delete(*self.product_list.get_children())
for product in self.products:
self.product_list.insert("", "end", values=(product.barcode, product.name, product.shelf_num, product.is_taken_out, product.last_watched, product.notes, product.physical_media))
def count_all_products(self): # New function to count products
count = len(self.products)
messagebox.showinfo("Physical Media Count", f"Total number of Physical Media: {count}")
def display_duplicate_products(self):
name_count = {}
for product in self.products:
if product.name in name_count:
name_count[product.name] += 1
else:
name_count[product.name] = 1
duplicates = {name for name, count in name_count.items() if count > 1}
self.product_list.delete(*self.product_list.get_children()) # Clear the existing list
sorted_products = sorted((product for product in self.products if product.name in duplicates), key=lambda x: x.name)
for product in sorted_products:
self.product_list.insert("", "end", values=(
product.barcode, product.name, product.shelf_num, product.is_taken_out,
product.last_watched, product.notes, product.physical_media
))
def save_products(self):
with open(os.path.join(self.appdata_path, "products.pkl"), "wb") as file:
pickle.dump(self.products, file)
def load_products(self):
if os.path.exists(os.path.join(self.appdata_path, "products.pkl")):
with open(os.path.join(self.appdata_path, "products.pkl"), "rb") as file:
self.products = pickle.load(file)
self.display_all_products()
def on_closing(self):
self.save_products()
self.root.destroy()
def sort_by_shelf_number(self):
self.products.sort(key=lambda x: x.shelf_num)
self.display_all_products()
def export_titles_to_txt(self):
if not self.products:
messagebox.showinfo("Export Titles", "No movies in the database to export!")
return
file_path = os.path.join(self.appdata_path, "movie_titles.txt")
with open(file_path, "w") as file:
for product in self.products:
file.write(product.name + "\n")
messagebox.showinfo("Export Titles", f"All movie titles have been exported to {file_path}")
if __name__ == "__main__":
root = tk.Tk()
root.withdraw() # Hide the root window initially
login_window = LoginWindow(root) # Show the login window
app = BarcodeApp(root) # Initialize the main app but don't show it yet
root.mainloop()