Sep-07-2023, 04:36 AM
I've finished the movie search script. Still a little ruff around the edges but, works. I had trouble placing text in the textbox so I went with using a frame in the textbox. That way I could kinda order the layout a little. I welcome any input. Remember it will take a few seconds to get the results as it does a few queries. My understanding of the imdb database may search through several pages to get the information.
# Do the imports from imdb import Cinemagoer import tkinter as tk from tkinter import ttk from urllib.request import urlopen from PIL import ImageTk, Image import io class Data: ''' The Data class retrieves all information from user input Searches person and movies returns all relevant information ''' def __init__(self): self.action = Cinemagoer() def search_person(self, name): person = self.action.search_person(name.strip())[0] return person.get('name'), person.personID def get_person(self, id): person = self.action.get_person(id) jobs = [job for job in person.get('filmography').keys()] movies = [movie for movie in person['filmography'][jobs[0]]] return person.get('name'), movies def search_movies(self, title): return self.action.search_movie(title) def get_movie(self, movie_id): if movie_id: movie = self.action.get_movie(movie_id) return movie class Window: ''' Window class is for visual and has fields and buttons for the Controller class to use ''' def __init__(self, parent): parent.columnconfigure(0, weight=1) parent.rowconfigure(0, weight=1) parent.minsize(800,600) parent['padx'] = 5 parent['pady'] = 3 parent['bg'] = '#c0c0c0' parent.title('Movie Search') container = tk.Frame(parent, bg='#333333') container.grid(column=0, row=0, sticky='news') container.grid_columnconfigure(0, weight=3) container.grid_rowconfigure(3, weight=3) header = tk.Label(container, text='Movie Search', fg='#ffffff', bg='#333333') header['font'] = 'tk.HEADER 28 bold' header.grid(column=0, row=0, sticky='new', padx=2, pady=2) self.msg = tk.Label(container, text='Messages: ', bg='#555555', fg='#FFFFFF', anchor='w', padx=10) self.msg['font'] = 'tk.MENU 13 normal' self.msg.grid(column=0, row=1, sticky='new', padx=2, pady=2) row1 = tk.Frame(container, bg='#555555') row1.grid(column=0, row=2, sticky='new', padx=2, pady=2) for i in range(5): weight = 4 if i == 3 else 3 row1.grid_columnconfigure(i, weight=weight, uniform='cols') row2 = tk.Frame(container, bg='#555555') row2.grid(column=0, row=3, sticky='news', padx=2, pady=2) row2.grid_columnconfigure(0, weight=3, uniform='tree') row2.grid_columnconfigure(2, weight=3, uniform='tree') row2.grid_rowconfigure(0, weight=3) row3 = tk.Frame(container, bg='#555555') row3.grid(column=0, row=4, sticky='new', padx=2, pady=2) row3.grid_columnconfigure(0, weight=3) label = tk.Label(row1, text='Search by:', bg='#555555', fg='#ffffff') label['font'] = 'None 12 normal' label.grid(column=0, row=0, sticky='new', padx=2, pady=4) self.options = ['Actors/Actresses', 'Movie Title'] self.picked = tk.StringVar() self.picked.set(self.options[0]) self.searchby = tk.OptionMenu(row1, self.picked, *self.options) self.searchby['font'] = 'None 10 normal' self.searchby.grid(column=1, row=0, sticky='new', padx=2, pady=4) self.searchby.config(border=0) label = tk.Label(row1, text='Search For:', bg='#555555', fg='#ffffff') label['font'] = 'None 12 normal' label.grid(column=2, row=0, sticky='new', padx=2, pady=4) self.entry = tk.Entry(row1) self.entry['font'] = 'None 12 normal' self.entry.grid(column=3, row=0, sticky='new', padx=2, pady=4) self.button = tk.Button(row1, text='Search') self.button.grid(column=4, row=0, sticky='new', padx=2) columns = ('Title', 'Released', 'Movie ID') self.left_tree = ttk.Treeview(row2, columns=columns, show='headings', selectmode='browse') for column in columns: if column == columns[0]: self.left_tree.column(column, minwidth=0, width=300, stretch='yes') else: self.left_tree.column(column, minwidth=0, width=100) self.left_tree.heading(column, text=column.title()) self.left_tree.grid(column=0, row=0, sticky='news', padx=2) left_scroll = tk.Scrollbar(row2, orient='vertical', command=self.left_tree.yview) self.left_tree.config(yscrollcommand=left_scroll.set) left_scroll.grid(column=1, row=0, sticky='ns', padx=2) self.textbox = tk.Text(row2) self.textbox.grid(column=2, row=0, sticky='news', padx=2) self.textbox.grid_columnconfigure(0, weight=3) textbox_scroll = tk.Scrollbar(row2, orient='vertical', command=self.textbox.yview) self.textbox.config(yscrollcommand=textbox_scroll.set) textbox_scroll.grid(column=3, row=0, sticky='ns', padx=2) sig = tk.Label(row3, text='my-python.org', bg='#333333', fg='#ffffff') sig['font'] = 'None 10 normal' sig.grid(column=0, row=0, sticky='new') class Controller: ''' Controller class handles all communications between the Data and Window class ''' def __init__(self, data, window): self.data = data self.window = window self.images = [] # Button Commands self.window.button['command'] = self.search #Dropdown command self.window.picked.trace('w', self.clear) # Bind treeview self.window.left_tree.bind('<<TreeviewSelect>>', self.details) def search(self): ''' Search method will lookup either actor or movie depending on the selection in the Window class. At the momment the search only works for finding actors and actresses ''' # Clear the views self.window.left_tree.delete(*self.window.left_tree.get_children()) self.window.textbox.delete('1.0', 'end') try: self.frame.destroy() except AttributeError: pass # Get the param for either person search or movie search picked = self.window.picked.get() # Get the name of the search. person or movie name = self.window.entry.get().strip() # Set alternation colors for the treeview self.window.left_tree.tag_configure('oddrow', background='#ccceee') self.window.left_tree.tag_configure('evenrow', background='white') # Clear the entry field self.window.entry.delete(0, 'end') # # Person was selected for search if picked == 'Actors/Actresses': self.window.msg['text'] = f'Messages: Search results for {name.title()}' # Call the Data class search_person method person = self.data.search_person(name.strip()) # Get relevant data using the person[1] which is set to the person id data = self.data.get_person(person[1]) # Create empty list to hold the data wanted movie_list = [] # Loop through the data getting relevant information # Also checking that there is a year for the movie release # This helps in not getting any movies not yet released for movie in data[1]: if movie.get('year'): movie_list.append((movie.get('title'), movie.get('year'), movie.movieID)) elif movie.get('year') == None: year = self.data.get_movie(movie.movieID).get('year') if year: movie_list.append((movie.get('title'), year, movie.movieID)) else: pass else: movies = self.data.search_movies(name.strip()) movie_list = [] for movie in movies: if movie.get('year'): movie_list.append((movie.get('title'), movie.get('year'), movie.movieID)) elif movie.get('year') == None: year = self.data.get_movie(movie.movieID).get('year') if year: movie_list.append((movie.get('title'), year, movie.movieID)) else: pass movie_list.sort(key=lambda year: year[1]) # Loop through the movie_list and insert into the treeview with alternating colors for index, movie in enumerate(movie_list): if index % 2 == 0: self.window.left_tree.insert('', index, values=(movie[0], movie[1], movie[2]), tags=('oddrow',)) else: self.window.left_tree.insert('', index, values=(movie[0], movie[1], movie[2]), tags=('evenrow',)) def details(self, id): item = self.window.left_tree.focus() try: id = self.window.left_tree.item(item)['values'][2] except IndexError: pass try: self.frame.destroy() except AttributeError: pass try: details = self.data.get_movie(id) title = details.get('title') cast = details.get('cast') year = details.get('year') plot = details.get('plot outline') cover = details.get('cover') rating = details.get('rating') air_date = details.get('original air date') cast_list = [c.get('name') for c in cast] cast = ', '.join(cast_list) img_url = urlopen(cover).read() img = Image.open(io.BytesIO(img_url)) image = ImageTk.PhotoImage(img) self.frame = tk.Frame(self.window.textbox,bg='white') self.frame.grid(column=0, row=0, sticky='news') self.frame.grid_columnconfigure(0, weight=3) label = tk.Label(self.frame, text=f'Title', anchor='w',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0,row=0,sticky='new',pady=8) label = tk.Label(self.frame, text=f'{title}', anchor='w',bg='white') label.grid(column=1,row=0,sticky='new',pady=8) label = tk.Label(self.frame, text=f'Year:', anchor='w',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=1, sticky='new',pady=8) label = tk.Label(self.frame, text=f'{year}', anchor='w',bg='white') label.grid(column=1, row=1, sticky='new',pady=8) label = tk.Label(self.frame, text=f'Air Date:', anchor='w',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=2, sticky='new',pady=8) label = tk.Label(self.frame, text=f'{air_date}', anchor='w',bg='white') label.grid(column=1, row=2, sticky='new',pady=8) label = tk.Label(self.frame, text=f'Cover Image:', image=image, compound='bottom',anchor='w',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=3, columnspan=2, sticky='new',pady=8) label = tk.Label(self.frame, text=f'Rating:', anchor='w',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=4, sticky='new',pady=8) label = tk.Label(self.frame, text=f'{rating}', anchor='w',bg='white') label.grid(column=1, row=4, sticky='new',pady=8) label = tk.Label(self.frame, text=f'Plot:', anchor='w', wraplength=800, justify='left',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=5, sticky='new',pady=8) label = tk.Label(self.frame, text=f'{plot}', anchor='w', wraplength=800, justify='left',bg='white') label.grid(column=1, row=5, sticky='new',pady=8) label = tk.Label(self.frame, text=f'Cast:', anchor='w', wraplength=800, justify='left',bg='white') label['font'] = 'tk.HEADER 10 bold' label.grid(column=0, row=6, sticky='new',pady=8) label = tk.Label(self.frame, text=f'{cast}', anchor='w', wraplength=800, justify='left',bg='white') label.grid(column=1, row=6, sticky='new',pady=8) self.window.textbox.delete('1.0', tk.END) self.window.textbox.insert('end', self.frame) self.images.append(image) except TypeError: pass def clear(self, write, index, mode): # Clear the treevies self.window.left_tree.delete(*self.window.left_tree.get_children()) self.window.textbox.delete('1.0', 'end') self.window.msg['text'] = 'Messages: ' try: self.frame.destroy() except AttributeError: pass if __name__ == '__main__': root = tk.Tk() img = urlopen('https://my-python.org/images/code-forum/light/light_on.png') data = img.read() image = tk.PhotoImage(data=data) root.wm_iconphoto(True, image) controller = Controller(Data(), Window(root)) root.mainloop()