def saveImage(track, audio, window): # store image data, width, and height from downloaded image into imageSelection field if track.imageSelection != "THUMB": # first clear all images from audio file audio["covr"] = '' # file image import will be used as a thumbnail in various windows fileImageImport = Image.open( resource_path('Temp/' + str(track.imageSelection) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) with open(resource_path('Temp/' + str(track.imageSelection) + '.jpg'), 'rb') as f: audio["covr"] = [f.read()] audio.save() track.imageSelection = [fileImageImport, width, height] # check if current track has artwork image else: if len(audio["covr"]) != 0: stream = BytesIO(audio["covr"][0]) image = Image.open(stream).convert("RGBA") stream.close() width, height = image.size image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, width, height] else: image = Image.open(resource_path('Thumbnail.png')) track.imageSelection = [image, '', ''] window.destroy()
def saveImage(track, audio, window): # store image data, width, and height from downloaded image into imageSelection field if track.imageSelection != "THUMB": # first clear all images from audio file audio.clear_pictures() # file image import will be used as a thumbnail in various windows fileImageImport = Image.open( resource_path('Temp/' + str(track.imageSelection) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) # image will be saved directly to the file image = Picture() with open(resource_path('Temp/' + str(track.imageSelection) + '.jpg'), 'rb') as f: image.data = f.read() image.type = id3.PictureType.COVER_FRONT image.mime = u"image/jpeg" audio.add_picture(image) audio.save() track.imageSelection = [fileImageImport, width, height] # check if current track has artwork image else: if len(audio.pictures) > 0: stream = BytesIO(audio.pictures[0].data) image = Image.open(stream).convert("RGBA") width, height = image.size image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, width, height] else: image = Image.open(resource_path('Thumbnail.png')) image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, '', ''] window.destroy()
def saveImage(track, audio, window): # store image data, width, and height from downloaded image into imageSelection field if track.imageSelection != "THUMB": # first clear all images from audio file audio.pop("APIC:") # file image import will be used as a thumbnail in various windows fileImageImport = Image.open( resource_path('Temp/' + str(track.imageSelection) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) with open(resource_path('Temp/' + str(track.imageSelection) + '.jpg'), 'rb') as f: audio["APIC:"] = APIC(encoding=3, mime=u"image/jpeg", type=id3.PictureType.COVER_FRONT, data=f.read()) audio.save() track.imageSelection = [fileImageImport, width, height] # check if current track has artwork image else: if audio["APIC:"] != b'': stream = BytesIO(audio["APIC:"].data) image = Image.open(stream).convert("RGBA") stream.close() width, height = image.size image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, width, height] else: image = Image.open(resource_path('Thumbnail.png')) image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, '', ''] window.destroy()
def extractInfo(soup, track, headers, webScrapingWindow, webScrapingLeftPane, webScrapingRightPane, webScrapingPage, webScrapingLinks, leftComponentFrame, rightComponentFrame, options, initialCounter, imageCounter, images): global count count += 1 # in case there are multiple genres scrapedGenreList = [] for link in soup.find_all('div', class_="content"): for link in link.find_all('a'): header = link['href'] # extract release date if "year" in header and "Release_Date" in options["Selected Tags (L)"]: # Discogs releases tend to have more credible tags, so each instance counts twice tk.Label(leftComponentFrame, text="Year: " + str(link.get_text().strip()), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') if " " in link.get_text().strip(): track.yearList.append(int(link.get_text().strip()[-4:])) track.yearList.append(int(link.get_text().strip()[-4:])) else: track.yearList.append(int(link.get_text().strip())) track.yearList.append(int(link.get_text().strip())) # extract genre elif "style" in header and "Genre" in options["Selected Tags (L)"]: genre = str(link.get_text()).strip() scrapedGenreList.append(genre) track.genreList.append(genre) genre = ', '.join(scrapedGenreList) if len(genre) >= 75: tk.Label(leftComponentFrame, text="Genre: " + genre[0:74] + "...", font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') else: tk.Label(leftComponentFrame, text="Genre: " + genre, font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') webScrapingLeftPane[webScrapingPage] = leftComponentFrame refresh(webScrapingWindow) try: image = soup.find('div', class_="image_gallery image_gallery_large")['data-images'] # extract image if "full" in image and ".jpg" in image and options["Extract Image from Website (B)"].get() == True and track.stop == False: link = image[image.index('full": ')+8:image.index(".jpg", image.index("full"))+4] # check if link[len(link)-5:len(link)-4]!='g': link = link + '.jpg' # write discogs image to drive with open(resource_path('Temp/' + str(imageCounter) + '.jpg'), "wb") as file: file.write(requests.get(link, headers=headers).content) track.URLList.append(link) # load file icon fileImageImport = Image.open(resource_path('Temp/' + str(imageCounter) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) images.append([fileImageImport, width, height]) photo = ImageTk.PhotoImage(fileImageImport) fileImage = tk.Label(rightComponentFrame, image=photo, bg=bg) fileImage.image = photo fileImage.pack(padx=(0, 100), anchor="e") imageCounter += 1 refresh(webScrapingWindow) webScrapingRightPane[webScrapingPage] = rightComponentFrame # perform image scraping if enabled in options if options["Reverse Image Search (B)"].get() == True and not track.stop: if not performSearch(initialCounter, imageCounter): imageCounter, images, track = reverseImageSearch(link, headers, imageCounter, images, track, options) except: pass return imageCounter, images, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage
def completeSearch(finalReportWindow, webScrapingWindow, options): finalReportWindow.destroy() if options["Close Scraping Window (B)"].get() != False: webScrapingWindow.destroy() else: webScrapingWindow.lift() # delete all images in temp if both revese image search and delete stored image options are both true if options["Delete Stored Images (B)"].get() == True: images = os.listdir(resource_path('Temp/')) for image in images: os.remove(resource_path('Temp/' + str(image)))
def scanTagsOnline(options, CONFIG_FILE, window): global imageCounter # delete all images stored in temp before proceeding if not os.path.isdir(resource_path('Temp/')): os.mkdir(resource_path('Temp/')) else: images = os.listdir(resource_path('Temp/')) for image in images: os.remove(resource_path('Temp/' + str(image))) webScrapingWindow, webScrapingPage = fileSelect(options, imageCounter, CONFIG_FILE, window) return webScrapingWindow, webScrapingPage
def addUncapitalizedList(keyword, popup): global change, capitalize, uncapitalize change = False capitalize = False uncapitalize = True CONFIG_FILE = resource_path('Settings.txt') config_file = open(CONFIG_FILE, 'r').read() # convert to term term = "Never Capitalize (L)" originalListValues = str( config_file[config_file.index(term) + len(term) + 1:config_file.index('\n', config_file.index(term) + len(term))]) newListValues = originalListValues if originalListValues == '': newListValues += keyword.lower() else: newListValues += ", " + keyword.lower() with open(CONFIG_FILE, 'wt') as file: file.write( config_file.replace( term + ":" + str(config_file[config_file.index(term) + len(term) + 1:config_file. index('\n', config_file.index(term) + len(term))]), term + ":" + str(newListValues))) file.close() popup.destroy()
def updatePreferences(options, CONFIG_FILE, root): window = tk.Toplevel(master=root) window.title("Preferences Window") ws = window.winfo_screenwidth() # width of the screen hs = window.winfo_screenheight() # height of the screen x = (ws / 2) - (780 / 2) y = (hs / 2) - (407 / 2) window.geometry('%dx%d+%d+%d' % (780, 370, x, y)) window.configure(bg=bg) tab_parent = ttk.Notebook(window) s = ttk.Style() try: s.theme_create("Track Management Utility", parent="alt", settings={ "TNotebook": {"configure": {"tabmargins": [2, 5, 2, 0], "background": secondary_bg, 'borderwidth': 0}}, "TNotebook.Tab": {"configure": {"padding": [13, 5], "font": ('Proxima Nova Rg', '11'), "background": secondary_bg, 'foreground': 'white', 'borderwidth': 1}, "map": {"background": [("selected", bg)], "expand": [("selected", [1, 1, 1, 0])] } } } ) except: pass s.theme_use("Track Management Utility") # web scraping tab webScrapingTab(tab_parent, options, CONFIG_FILE) # tagging tab taggingTab(tab_parent, options, CONFIG_FILE) # naming tab namingTab(tab_parent, options, CONFIG_FILE) # drive comparison tab comparisonTab(tab_parent, options, CONFIG_FILE) window.iconbitmap(resource_path('favicon.ico')) root.mainloop()
def saveThumbnail(image, thumbnails): if image != "NA": width, height = image.size image = image.resize((200, 200), Image.ANTIALIAS) thumbnails.append([image, width, height]) else: fileImageImport = Image.open(resource_path('Thumbnail.png')) fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) thumbnails.append([fileImageImport, '', '']) return thumbnails
def createConfigFile(flag): CONFIG_FILE = resource_path('Settings.txt') if flag == 'F' or (flag == "N" and not os.path.exists(CONFIG_FILE)): # create setttings file file = open(CONFIG_FILE, 'w') file.write( "-GENERAL-\nSubdirectories (B):True\nClose Scraping Window (B):True\nFirst Default Directory (S):\nSecond Default Directory (S):\nCopy Directory Contents (B):True\n\n" "-SCRAPING SETTINGS-\nScrape Junodownload (B):True\nScrape Beatport (B):True\nScrape Discogs (B):True\nExtract Image from Website (B):True\nLimit Number of Matches per Site (B):True\nMatch Limit (I):4\n\n" "-IMAGE SCRAPING-\nReverse Image Search (B):True\nDelete Stored Images (B):True\nImage Load Wait Time (I):5\nNumber of Images Per Page (I):3\nStop Search After Conditions (B):True\nStop Search After Finding Image of Resolution (S):2000x2000\nHide Selenium Browser (B):True\n\n" "-TAGGING-\nScan Filename and Tags (B):True\nCheck for Numbering Prefix (B):True\nCheck for Extraneous Hyphens (B):True\nCheck for Underscores (B):True\nCheck for Capitalization (B):True\nAlways Capitalize (L):\nNever Capitalize (L):\nAudio naming format (S):Dynamic\nSelected Tags (L):Artist, BPM, Genre, Image, Key, Release_Date, ReplayGain, Title\nDelete Unselected Tags (B):False\n" ) file.close() return CONFIG_FILE
def saveImage(track, audio, window): # store image data, width, and height from downloaded image into imageSelection field if track.imageSelection != "THUMB": image = Picture() # first clear all images from audio file audio['metadata_block_picture'] = '' # file image import will be used as a thumbnail in various windows fileImageImport = Image.open( resource_path('Temp/' + str(track.imageSelection) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) with open(resource_path('Temp/' + str(track.imageSelection) + '.jpg'), 'rb') as f: image.data = f.read() image.type = 17 image.mime = u"image/jpeg" image = image.write() value = base64.b64encode(image) value = value.decode("ascii") audio['metadata_block_picture'] = [value] audio.save() track.imageSelection = [fileImageImport, width, height] # check if current track has artwork image else: if audio["metadata_block_picture"][0] != '': data = base64.b64decode(audio["metadata_block_picture"][0]) image = Picture(data) stream = BytesIO(image.data) image = Image.open(stream).convert("RGBA") stream.close() width, height = image.size image = image.resize((200, 200), Image.ANTIALIAS) track.imageSelection = [image, width, height] else: image = Image.open(resource_path('Thumbnail.png')) track.imageSelection = [image, '', ''] window.destroy()
def deleteKeyword(term, listbox, index, select, options): CONFIG_FILE = resource_path('Settings.txt') config_file = open(CONFIG_FILE, 'r').read() # convert to term originalListValues = options[term] newListValues = originalListValues originalListValues = ", ".join(originalListValues) newListValues.remove(listbox.get(index)) newListValues.sort() newListValues = ", ".join(newListValues) with open(CONFIG_FILE, 'wt') as file: file.write( config_file.replace(term + ":" + originalListValues, term + ":" + newListValues)) file.close() # remove from listbox listbox.delete(index, index) # disable delete button select.config(state=DISABLED)
def addKeywordToList(term, alternateTerm, capitalizeAdd, uncapitalizeAdd, listbox, userInput, options, popup): # re-enable add buttons capitalizeAdd.config(state=NORMAL) uncapitalizeAdd.config(state=NORMAL) if userInput.get().lower() in (string.lower() for string in options[term]): messagebox.showinfo(parent=popup, title="Error", message=userInput.get().lower() + " is already in the list, you cretin") userInput.set("") elif userInput.get().lower() in (string.lower() for string in options[alternateTerm]): messagebox.showinfo( parent=popup, title="Error", message=userInput.get().lower() + " is already in the other list; keywords cannot be stored in both lists" ) userInput.set("") else: CONFIG_FILE = resource_path('Settings.txt') config_file = open(CONFIG_FILE, 'r').read() # convert to term originalListValues = options[term] newListValues = originalListValues originalListValues = ", ".join(originalListValues) newListValues.append(userInput.get()) newListValues.sort() newListValues = ", ".join(newListValues) with open(CONFIG_FILE, 'wt') as file: file.write( config_file.replace(term + ":" + originalListValues, term + ":" + newListValues)) file.close() # add to the keywords listbox listbox.insert(END, userInput.get()) popup.destroy()
def handleArtistTitleDiscrepancy(fileArtist, tagArtist, fileTitle, tagTitle): global file global tag popup = tk.Toplevel() popup.title("Tag Filename Mismatch - Title") ws = popup.winfo_screenwidth() # width of the screen hs = popup.winfo_screenheight() # height of the screen x = (ws / 2) - (550 / 2) y = (hs / 2) - (330 / 2) if len(fileTitle) <= 30: popup.geometry('%dx%d+%d+%d' % (550, 300, x, y)) else: x = (ws / 2) - ((450 + (len(fileTitle) * 1.5)) / 2) popup.geometry('%dx%d+%d+%d' % (550 + (len(fileTitle) * 1.5), 300, x, y)) popup.config(bg=bg) tk.Label( popup, text= "The title and artist in filename conflict with their corresponding tags.\nChoose between the file and tag name\n", font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(pady=(20, 10)) # pack a label for each individual word in the file name tk.Label(popup, text="File Name", font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack() filename = re.split( "_space_|_hyphen_", fileArtist.replace(' ', '_space_ _space_').replace('-', '_hyphen_-_hyphen_')) filename.append(' - ') filename += re.split( "_space_|_hyphen_", fileTitle.replace(' ', '_space_ _space_').replace('-', '_hyphen_-_hyphen_')) filenameContainer = tk.Label(popup, justify="left", bg=bg) filenameContainer.pack(pady=(0, 15)) filenameDict = {} for i in range(len(filename)): filenameDict[i] = tk.Label(filenameContainer, text=filename[i], borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg) filenameDict[i].pack(side="left") # if i != len(filename) - 1: tk.Label(filenameContainer, text='', borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side="left") # pack a label for each individual word in the tag name tk.Label(popup, text="Tag Name", font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(pady=(20, 0)) tagname = re.split( "_space_|_hyphen_", tagArtist.replace(' ', '_space_ _space_').replace('-', '_hyphen_-_hyphen_')) tagname.append(' - ') tagname += re.split( "_space_|_hyphen_", tagTitle.replace(' ', '_space_ _space_').replace('-', '_hyphen_-_hyphen_')) tagnameContainer = tk.Label(popup, justify="left", bg=bg) tagnameContainer.pack(pady=(0, 10)) tagnameDict = {} for i in range(len(tagname)): tagnameDict[i] = tk.Label(tagnameContainer, text=tagname[i], borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg) tagnameDict[i].pack(side="left") # highlight word if it does not match with the current filename if len(filename) == len(tagname) and filename[i] != tagname[i]: filenameDict[i].configure(fg="black", background="yellow") tagnameDict[i].configure(fg="black", background="yellow") buttons = tk.Frame(popup, bg=bg) buttons.pack(side="top") tk.Button(buttons, text='File Name', command=lambda: selectFile(popup), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(pady=(25, 10), padx=(10, 30), side="left") tk.Button(buttons, text='Tag Name', command=lambda: selectTag(popup), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(pady=(25, 10), padx=(30, 10), side="left") popup.protocol("WM_DELETE_WINDOW", lambda: popup.destroy()) popup.iconbitmap(resource_path('favicon.ico')) popup.wait_window() if file == True: file = False return "file" elif tag == True: tag = False return "tag"
def ID3_conflict(audio, track, options, initialCounter, imageCounter, images, informalTagDict): global page page = 0 tagAlert = False if "Release_Date" in options["Selected Tags (L)"] and audio["TDRC"] != '': tagAlert = True if "BPM" in options["Selected Tags (L)"] and audio["TBPM"] != '': tagAlert = True if "Key" in options["Selected Tags (L)"] and audio["TKEY"] != '': tagAlert = True if "Genre" in options["Selected Tags (L)"] and audio["TCON"] != '': tagAlert = True if tagAlert: # tag conflict tagConflict = False if "Release_Date" in options["Selected Tags (L)"] and str( audio["TDRC"]) != str(track.release_date): tagConflict = True if "BPM" in options["Selected Tags (L)"] and str(audio["TBPM"]) != str( track.bpm): tagConflict = True if "Key" in options["Selected Tags (L)"] and str( audio["TKEY"]) != track.key: tagConflict = True if "Genre" in options["Selected Tags (L)"] and str( audio["TCON"]) != track.genre: tagConflict = True if tagConflict: conflictPopup = tk.Toplevel() conflictPopup.title("Conflicting Tags") ws = conflictPopup.winfo_screenwidth() # width of the screen hs = conflictPopup.winfo_screenheight() # height of the screen x = (ws / 2) - (650 / 2) y = (hs / 2) - (264 / 2) conflictPopup.geometry('%dx%d+%d+%d' % (650, 240, x, y)) if len(str(track.artist) + " - " + str(track.title)) > 30: x = (ws / 2) - ( (650 + (len(str(track.artist) + " - " + str(track.title)) * 1.5)) / 2) conflictPopup.geometry( '%dx%d+%d+%d' % ((650 + (len(str(track.artist) + " - " + str(track.title)) * 1.5)), 240, x, y)) conflictPopup.config(bg=bg) # tag conflict window tk.Label(conflictPopup, text="Conflicting tags in " + str(track.artist) + " - " + str(track.title), font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(pady=(30, 40), side="top") tags = tk.Frame(conflictPopup, bg=bg) tags.pack() # print current tags leftTags = tk.Frame(tags, bg=bg) leftTags.pack(side="left", padx=(0, 50), pady=(0, 50)) currentTagDict = {} scrapedTagDict = {} list = [] if "Release_Date" in options["Selected Tags (L)"]: list.append("Release_Date") conflictPopup.update_idletasks() y = (hs / 2) - (( (conflictPopup.winfo_height() + 10) * 1.1) / 2) conflictPopup.geometry( '%dx%d+%d+%d' % (conflictPopup.winfo_width(), conflictPopup.winfo_height() + 20, x, y)) if "BPM" in options["Selected Tags (L)"]: list.append("BPM") conflictPopup.update_idletasks() y = (hs / 2) - (( (conflictPopup.winfo_height() + 10) * 1.1) / 2) conflictPopup.geometry( '%dx%d+%d+%d' % (conflictPopup.winfo_width(), conflictPopup.winfo_height() + 20, x, y)) if "Key" in options["Selected Tags (L)"]: list.append("Key") conflictPopup.update_idletasks() y = (hs / 2) - (( (conflictPopup.winfo_height() + 10) * 1.1) / 2) conflictPopup.geometry( '%dx%d+%d+%d' % (conflictPopup.winfo_width(), conflictPopup.winfo_height() + 20, x, y)) if "Genre" in options["Selected Tags (L)"]: list.append("Genre") conflictPopup.update_idletasks() y = (hs / 2) - (( (conflictPopup.winfo_height() + 10) * 1.1) / 2) conflictPopup.geometry( '%dx%d+%d+%d' % (conflictPopup.winfo_width(), conflictPopup.winfo_height() + 20, x, y)) currentTagDict[0] = tk.Label(leftTags, text="CURRENT TAGS:", font=("Proxima Nova Rg", 11), fg="white", bg=bg, justify="left", bd=-10) currentTagDict[0].pack(anchor="w", pady=(0, 15)) for i in range(len(list)): # avoid printing the underscore if list[i] == "Release_Date": currentTagDict[i + 1] = tk.Label( leftTags, text="Release Date: " + str(audio[informalTagDict[list[i]]]), font=("Proxima Nova Rg", 11), fg="white", bg=bg) currentTagDict[i + 1].pack(pady=(0, 0), anchor='w') else: currentTagDict[i + 1] = tk.Label( leftTags, text=list[i] + ": " + str(audio[informalTagDict[list[i]]]), font=("Proxima Nova Rg", 11), fg="white", bg=bg) currentTagDict[i + 1].pack(pady=(0, 0), anchor='w') # print scraped tags rightTags = tk.Frame(tags, bg=bg) rightTags.pack(side="right", padx=(50, 0), pady=(0, 50)) scrapedTagDict[0] = tk.Label(rightTags, text="SCRAPED TAGS:", font=("Proxima Nova Rg", 11), fg="white", bg=bg, justify="left", bd=-10) scrapedTagDict[0].pack(anchor="w", pady=(0, 15)) for i in range(len(list)): # Avoid printing the underscore if list[i] == "Release_Date": scrapedTagDict[i + 1] = tk.Label( rightTags, text="Release Date: " + str(getattr(track, list[i].lower())), font=("Proxima Nova Rg", 11), fg="white", bg=bg) else: scrapedTagDict[i + 1] = tk.Label( rightTags, text=list[i] + ": " + str(getattr(track, list[i].lower())), font=("Proxima Nova Rg", 11), fg="white", bg=bg) scrapedTagDict[i + 1].pack(pady=(0, 0), anchor='w') # check if both tag dictionaries are of equal length if len(currentTagDict) == len(scrapedTagDict): for i in range(1, len(currentTagDict)): # highlight yellow if str(currentTagDict[i]["text"]) != str( scrapedTagDict[i]["text"]): currentTagDict[i].config(fg="black", bg="yellow") scrapedTagDict[i].config(fg="black", bg="yellow") # buttons optionButtons = tk.Frame(conflictPopup, bg=bg) optionButtons.pack() tk.Button(optionButtons, text="Overwrite All", command=lambda: overwriteAllOption( audio, track, options, conflictPopup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(side="left", padx=(20, 20)) tk.Button(optionButtons, text="Overwrite Blanks", command=lambda: overwriteBlanksOption( audio, track, options, conflictPopup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(side="left", padx=(20, 20)) tk.Button(optionButtons, text="Skip", command=lambda: skipOption(audio, track, options, conflictPopup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(side="left", padx=(20, 20)) conflictPopup.attributes("-topmost", True) conflictPopup.iconbitmap(resource_path('favicon.ico')) conflictPopup.wait_window() else: if "Release_Date" in options["Selected Tags (L)"]: audio["TDRC"] = TDRC(encoding=3, text=str(track.release_date)) if "BPM" in options["Selected Tags (L)"]: audio["TBPM"] = TBPM(encoding=3, text=str(track.bpm)) if "Key" in options["Selected Tags (L)"]: audio["TKEY"] = TKEY(encoding=3, text=track.key) if "Genre" in options["Selected Tags (L)"]: audio["TCON"] = TCON(encoding=3, text=track.genre) audio.save() # image conflict if imageCounter - initialCounter >= 1: buttons = [] conflictPopup = tk.Toplevel() conflictPopup.title("Conflicting Images") ws = conflictPopup.winfo_screenwidth() # width of the screen hs = conflictPopup.winfo_screenheight() # height of the screen y = (hs / 2) - (803 / 2) x = (ws / 2) - ((350 + (200 * min( (imageCounter - initialCounter), options["Number of Images Per Page (I)"].get()))) / 2) conflictPopup.geometry('%dx%d+%d+%d' % (350 + (200 * min( (imageCounter - initialCounter), options["Number of Images Per Page (I)"].get())), 730, x, y)) conflictPopup.config(bg=bg) # print current thumbnail tk.Label(conflictPopup, text="Current artwork", font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(pady=(20, 10)) thumbnailFrame = tk.Frame(conflictPopup, bg=bg) thumbnailFrame.pack() image = audio["APIC:"] if image != b'': stream = BytesIO(image.data) image = Image.open(stream).convert("RGBA") stream.close() width, height = image.size thumbnailImageImport = image.resize((200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(thumbnailImageImport) thumbnailImage = tk.Label(conflictPopup, image=photo) thumbnailImage.image = photo thumbnailButton = tk.Button( thumbnailFrame, image=photo, bg="yellow", highlightcolor='yellow', highlightthickness=3, command=lambda: selectImage("THUMB", track, thumbnailButton, buttons, conflictPopup)) thumbnailButton.pack(side="top") buttons.append(thumbnailButton) tk.Label(conflictPopup, text=str(width) + "x" + str(height), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side="top", pady=(5, 10)) thumbnail = [thumbnailImageImport, width, height] else: thumbnail = "NA" fileImageImport = Image.open(resource_path('Thumbnail.png')) fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(fileImageImport) fileImage = tk.Label(thumbnailFrame, image=photo, bg=bg) fileImage.image = photo thumbnailButton = tk.Button( thumbnailFrame, image=photo, font=("Proxima Nova Rg", 11), bg="yellow", highlightcolor='yellow', highlightthickness=3, command=lambda: selectImage("THUMB", track, thumbnailButton, buttons, conflictPopup)) thumbnailButton.pack(side="top", pady=(5, 10)) buttons.append(thumbnailButton) tk.Label(conflictPopup, text="Scraped artwork", font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(side="top", pady=(15, 10)) imageFrame = tk.Frame(conflictPopup, bg=bg) imageFrame.pack(side="top") # print images as buttons start = initialCounter end = imageCounter resolutionsFrame = tk.Frame(conflictPopup, bg=bg) resolutionsFrame.pack(side="top") loadImageButtons(start, end, imageFrame, images, resolutionsFrame, conflictPopup, track, buttons, page, options) # page indicator pageFrame = tk.Frame(conflictPopup, bg=bg) pageFrame.pack() # load navigational buttons and page number loadNavigation(start, end, pageFrame, imageFrame, images, resolutionsFrame, conflictPopup, thumbnailFrame, track, thumbnail, page, "load", options) # select button tk.Button(conflictPopup, text="Select", font=("Proxima Nova Rg", 11), fg="white", bg=bg, command=lambda: saveImage(track, audio, conflictPopup)).pack( side="top", pady=(25, 10)) conflictPopup.attributes("-topmost", True) conflictPopup.iconbitmap(resource_path('favicon.ico')) conflictPopup.wait_window()
def junodownloadSearch(filename, track, artistVariations, titleVariations, headers, search, webScrapingWindow, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage, labelFrame, searchFrame, pageFrame, componentFrame, audio, options, initialCounter, imageCounter, images): global count count = 0 widgetList = allWidgets(searchFrame) for item in widgetList: item.pack_forget() if len(filename) > 60: tk.Label(searchFrame, text="\nSearching Juno Download for " + str(filename)[0:59] + "...", font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(side="left", padx=(10, 0), anchor='w') else: tk.Label(searchFrame, text="\nSearching Juno Download for " + str(filename), font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(side="left", padx=(10, 0), anchor='w') leftComponentFrame, rightComponentFrame = resetLeftRightFrames( componentFrame) refresh(webScrapingWindow) url = "https://www.google.co.in/search?q=" + search + " Junodownload" soup = prepareRequest(url, headers, webScrapingWindow, leftComponentFrame) if soup != False: for result in soup.find_all('div', class_="ZINbbc xpd O9g5cc uUPGi"): if 'junodownload.com' and 'products' in result.find('a').get( 'href').split('&')[0].lower(): resultString = str(result).replace('&', 'and').lower() for variation in titleVariations: variation = variation.replace('-', ' ') if variation.lower() in resultString: link = result.find('a').get('href').split('&')[0][7:] refresh(webScrapingWindow) soup = prepareRequest(link, headers, webScrapingWindow, leftComponentFrame) if soup != False: # post link to web scraping window widgetList = allWidgets(componentFrame) for widget in widgetList: widget.pack_forget() widgetList = allWidgets(pageFrame) for widget in widgetList: widget.pack_forget() # increment web scraping page and rerender count webScrapingPage += 1 leftComponentFrame, rightComponentFrame = resetLeftRightFrames( componentFrame) rerenderControls(pageFrame, webScrapingPage) if len(link) >= 75: label = tk.Label(leftComponentFrame, text="\n" + str(link)[0:74] + "...", cursor="hand2", font=("Proxima Nova Rg", 11), fg="white", bg=bg) else: label = tk.Label(leftComponentFrame, text="\n" + str(link), cursor="hand2", font=("Proxima Nova Rg", 11), fg="white", bg=bg) label.bind( "<Button-1>", lambda e, link=link: webbrowser.open_new(link)) label.pack(padx=(10, 0), pady=(0, 25), anchor='w') # update left component history frame webScrapingLeftPane[ webScrapingPage] = leftComponentFrame # assume match will fail and no image will be found webScrapingRightPane[webScrapingPage] = "NA" # update link webScrapingLinks[webScrapingPage] = link finalMatch = False # search individual listings in table for item in soup.find_all( 'div', class_= "row gutters-sm align-items-center product-tracklist-track" ): name = item.find('span').get_text() if ' - ' in name: trackArtist = item.find( 'span').get_text().split(' - ')[0] trackTitle = item.find( 'span').get_text().split(' - ')[1] else: trackArtist = '' trackTitle = item.find('span').get_text() if not compareTokens(variation, trackTitle): # check runtime to ensure track is correct runtime = item.find( 'div', class_= "col-1 d-none d-lg-block text-center" ).get_text() if not compareRuntime(runtime, audio): count += 1 finalMatch = True for value in item.find_all( 'div', class_= "col-1 d-none d-lg-block text-center" ): # extract BPM if ":" not in value.get_text( ) and value.get_text( ) != '\xa0' and "BPM" in options[ "Selected Tags (L)"]: BPM = value.get_text() tk.Label( leftComponentFrame, text="BPM: " + str(BPM), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') webScrapingLeftPane[ webScrapingPage] = leftComponentFrame refresh(webScrapingWindow) track.BPMList.append(int(BPM)) track.BPMList.append(int(BPM)) # only push release and genre from header if title is found in tracklist for data in soup.select( 'div[class=mb-3]'): # extract release date if "Release_Date" in options[ "Selected Tags (L)"]: release = data.find( "span", itemprop="datePublished" ).get_text() tk.Label( leftComponentFrame, text="Year: " + str(release), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') track.yearList.append( int(release[-4:])) # extract genre if "Genre" in options[ "Selected Tags (L)"]: genre = data.find( "a").get_text() tk.Label( leftComponentFrame, text="Genre: " + str(genre), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor='w') track.genreList.append(genre) webScrapingLeftPane[ webScrapingPage] = leftComponentFrame # extract image if options[ "Extract Image from Website (B)"].get( ) == True and track.stop == False: try: item = soup.find( 'div', class_="jw-page") item = item.find('img').get( 'data-src-full') # write junodownload image to drive with open( resource_path( 'Temp/' + str(imageCounter) + '.jpg'), "wb") as file: file.write( requests.get( item, headers=headers). content) track.URLList.append(item) # load file icon fileImageImport = Image.open( resource_path( 'Temp/' + str(imageCounter) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize( (200, 200), Image.ANTIALIAS) images.append([ fileImageImport, width, height ]) photo = ImageTk.PhotoImage( fileImageImport) fileImage = tk.Label( rightComponentFrame, image=photo, bg=bg) fileImage.image = photo fileImage.pack(padx=(0, 100), anchor="e") imageCounter += 1 refresh(webScrapingWindow) webScrapingRightPane[ webScrapingPage] = rightComponentFrame # perform image scraping if enabled in options if options[ "Reverse Image Search (B)"].get( ) == True and not track.stop: if not performSearch( initialCounter, imageCounter): imageCounter, images, track = reverseImageSearch( item, headers, imageCounter, images, track, options) except: pass # avoid counting the same entry twice if not finalMatch: tk.Label( leftComponentFrame, text= "Track did not match with any of the listings", font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) break if options['Limit Number of Matches per Site (B)'].get( ) and count >= options['Match Limit (I)'].get(): break return track, imageCounter, images, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage, searchFrame, pageFrame, componentFrame
AddFontResourceEx = windll.gdi32.AddFontResourceExW else: raise TypeError('fontpath must be of type str or unicode') flags = (FR_PRIVATE if private else 0) | (FR_NOT_ENUM if not enumerable else 0) numFontsAdded = AddFontResourceEx(byref(pathbuf), flags, 0) return bool(numFontsAdded) proximaNovaRegular = False proximaNovaBold = False # check if font proxima nova is installed for font in font_manager.win32InstalledFonts(): if 'proxima nova bold' in font.lower(): proximaNovaBold = True elif 'proxima nova' in font.lower(): proximaNovaRegular = True if not proximaNovaRegular: loadfont(resource_path('Proxima Nova Regular.ttf')) if not proximaNovaBold: loadfont(resource_path('Proxima Nova Bold.ttf')) # global variables bg = "#282f3b" # main bg color secondary_bg = "#364153" # secondary color window = False # main driver code root = tk.Tk() root.title("Track Management Utility V1.0") ws = root.winfo_screenwidth() # width of the screen hs = root.winfo_screenheight() # height of the screen x = (ws / 2) - (1000 / 2) y = (hs / 2) - (660 / 2) root.geometry('%dx%d+%d+%d' % (1000, 600, x, y))
def directorySearch(first_directory, second_directory, directoryFileCount, differenceCount, directoryCount, options): if complete == True: return differenceCount, directoryCount first_directory_files = os.listdir(first_directory) second_directory_files = os.listdir(second_directory) for var in first_directory_files: # check if file var is a directory if os.path.isdir(str(first_directory) + '/' + str(var)) and complete == False: # check if second_directory has the same directory if var not in second_directory_files: directoryCount += 1 popup = tk.Toplevel() popup.title("Directory Conflict Detected") ws = popup.winfo_screenwidth() # width of the screen hs = popup.winfo_screenheight() # height of the screen x = (ws / 2) - (550 / 2) y = (hs / 2) - (275 / 2) popup.geometry('%dx%d+%d+%d' % (550, 250, x, y)) popup.config(bg=bg) if len( [name for name in os.listdir(first_directory + '/' + var) ]) == 1: tk.Label(popup, text=var + " (1 file inside)", wraplength=500, font=('Proxima Nova Rg', 13), fg="white", bg=bg).pack(pady=(20, 20)) else: tk.Label(popup, text=var + " (" + str( len([ name for name in os.listdir(first_directory + '/' + var) ])) + " files inside)", wraplength=500, font=('Proxima Nova Rg', 13), fg="white", bg=bg).pack(pady=(20, 20)) tk.Label(popup, text="Found in " + first_directory, wraplength=500, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack() tk.Label(popup, text="Not found in " + second_directory, wraplength=500, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(pady=(20, 20)) buttonFrame = tk.Frame(popup, bg=bg) buttonFrame.pack(pady=(35, 0)) tk.Button(buttonFrame, text='Copy', command=lambda: copyDirectory( first_directory, second_directory, var, options, popup), font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) tk.Button(buttonFrame, text='Delete', command=lambda: deleteDirectory( first_directory, var, popup), font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) tk.Button(buttonFrame, text='Ignore', command=popup.destroy, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) popup.protocol("WM_DELETE_WINDOW", lambda arg=popup: on_exit(arg)) popup.iconbitmap(resource_path('favicon.ico')) popup.wait_window() # check files within that directory with those in the directory of second_directory else: directoryFileCount, differenceCount, directoryCount = directorySearch( first_directory + '/' + var, second_directory + '/' + var, directoryFileCount, differenceCount, directoryCount, options) elif complete == False: directoryFileCount += 1 # check if second_directory has the same file if var not in second_directory_files: differenceCount += 1 popup = tk.Toplevel() popup.title("File Conflict Detected") ws = popup.winfo_screenwidth() # width of the screen hs = popup.winfo_screenheight() # height of the screen x = (ws / 2) - (550 / 2) y = (hs / 2) - (275 / 2) popup.geometry('%dx%d+%d+%d' % (550, 250, x, y)) if len(var) > 65: x = (ws / 2) - ((550 + ((len(var) - 65) * 9)) / 2) popup.geometry('%dx%d+%d+%d' % ((550 + ((len(var) - 65) * 9)), 270, x, y)) popup.config(bg=bg) tk.Label(popup, text=var, font=('Proxima Nova Rg', 13), fg="white", bg=bg).pack(pady=(25, 26)) tk.Label(popup, text="Present in " + first_directory, wraplength=500, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(pady=(0, 30)) tk.Label(popup, text="Missing in " + second_directory, wraplength=500, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(pady=(0, 30)) # artwork from FLAC if var.endswith(".flac"): audio = FLAC(first_directory + '/' + var) picture = audio.pictures if len(picture) > 0: y = (hs / 2) - (550 / 2) popup.update_idletasks() popup.geometry('%dx%d+%d+%d' % (popup.winfo_width(), 500, x, y)) stream = BytesIO(picture[0].data) image = Image.open(stream).convert("RGBA") stream.close() directoryImageImport = image.resize((200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(directoryImageImport) directoryImage = tk.Label(popup, image=photo, bg=bg) directoryImage.image = photo directoryImage.pack(side="top", pady=(0, 30)) # artwork from MP3, AIFF, or WAV elif var.endswith(".mp3") or var.endswith( ".aiff") or var.endswith(".wav"): audio = MP3(first_directory + '/' + var) if 'APIC:' in audio: image = audio["APIC:"] if image != b'': y = (hs / 2) - (550 / 2) popup.geometry('%dx%d+%d+%d' % (550, 500, x, y)) stream = BytesIO(image.data) image = Image.open(stream).convert("RGBA") stream.close() directoryImageImport = image.resize( (200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(directoryImageImport) directoryImage = tk.Label(popup, image=photo, bg=bg) directoryImage.image = photo directoryImage.pack(side="top", pady=(0, 30)) # artwork from OGG elif var.endswith(".ogg"): audio = OggVorbis(first_directory + '/' + var) if "metadata_block_picture" in audio: imageFrame = audio["metadata_block_picture"] if imageFrame[0] != '': y = (hs / 2) - (550 / 2) popup.geometry('%dx%d+%d+%d' % (550, 500, x, y)) data = base64.b64decode(imageFrame[0]) image = Picture(data) stream = BytesIO(image.data) image = Image.open(stream).convert("RGBA") stream.close() directoryImageImport = image.resize( (200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(directoryImageImport) directoryImage = tk.Label(popup, image=photo, bg=bg) directoryImage.image = photo directoryImage.pack(side="top", pady=(0, 30)) # artwork from M4A elif var.endswith(".m4a"): audio = MP4(first_directory + '/' + var) if "covr" in audio: image = audio["covr"] if len(image) != 0: y = (hs / 2) - (550 / 2) popup.geometry('%dx%d+%d+%d' % (550, 500, x, y)) stream = BytesIO(image[0]) image = Image.open(stream).convert("RGBA") stream.close() directoryImageImport = image.resize( (200, 200), Image.ANTIALIAS) photo = ImageTk.PhotoImage(directoryImageImport) directoryImage = tk.Label(popup, image=photo, bg=bg) directoryImage.image = photo directoryImage.pack(side="top", pady=(0, 30)) buttonFrame = tk.Frame(popup, bg=bg) buttonFrame.pack(pady=(10, 10)) tk.Button(buttonFrame, text='Copy', command=lambda: copyFile( first_directory, second_directory, var, popup), font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) tk.Button( buttonFrame, text='Delete', command=lambda: deleteFile(first_directory, var, popup), font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) tk.Button(buttonFrame, text='Ignore', command=popup.destroy, font=('Proxima Nova Rg', 11), fg="white", bg=bg).pack(side="left", padx=(20, 20)) popup.protocol("WM_DELETE_WINDOW", lambda arg=popup: on_exit(arg)) popup.iconbitmap(resource_path('favicon.ico')) popup.wait_window() return directoryFileCount, differenceCount, directoryCount
def extractInfo(soup, track, headers, leftComponentFrame, rightComponentFrame, webScrapingWindow, webScrapingLeftPane, webScrapingRightPane, webScrapingPage, options, initialCounter, imageCounter, images): global count count += 1 for link in soup.find_all('ul', class_="interior-track-content-list"): # extract release date if "Release_Date" in options["Selected Tags (L)"]: release = link.find('li', class_="interior-track-content-item interior-track-released") release = release.find('span', class_="value").get_text() tk.Label(leftComponentFrame, text="Year: " + str(release[0:4]), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) track.yearList.append(int(release[0:4])) # extract BPM if "BPM" in options["Selected Tags (L)"]: BPM = link.find('li', class_="interior-track-content-item interior-track-bpm") BPM = BPM.find('span', class_="value").get_text() tk.Label(leftComponentFrame, text="BPM: " + str(BPM), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) track.BPMList.append(int(BPM)) # extract key if "Key" in options["Selected Tags (L)"]: key = link.find('li', class_="interior-track-content-item interior-track-key") key = key.find('span', class_="value").get_text() tk.Label(leftComponentFrame, text="Key: " + str(key), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) track.keyList.append(key) # extract genre if "Genre" in options["Selected Tags (L)"]: genre = link.find('li', class_="interior-track-content-item interior-track-genre") if genre.find('span', class_="value sep"): firstGenre = genre.find('span', class_="value") firstGenre = firstGenre.find('a').get_text() secondGenre = genre.find('span', class_="value sep") secondGenre = secondGenre.find('a').get_text() tk.Label(leftComponentFrame, text="Genre: " + str(firstGenre) + ' | ' + str(secondGenre), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) track.genreList.append(firstGenre) track.genreList.append(secondGenre) else: genre = genre.find('span', class_="value") genre = genre.find('a').get_text() tk.Label(leftComponentFrame, text="Genre: " + str(genre), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(padx=(10, 0), pady=(5, 0), anchor="w") refresh(webScrapingWindow) track.genreList.append(genre) webScrapingLeftPane[webScrapingPage] = leftComponentFrame # extract image if options["Extract Image from Website (B)"].get() == True and track.stop == False: link = soup.find('img', class_="interior-track-release-artwork") if link!=None: link = link['src'] # write beatport image to drive with open(resource_path('Temp/' + str(imageCounter) + '.jpg'), "wb") as file: file.write(requests.get(link, headers=headers).content) track.URLList.append(link) # load file icon try: fileImageImport = Image.open(resource_path('Temp/' + str(imageCounter) + '.jpg')) width, height = fileImageImport.size fileImageImport = fileImageImport.resize((200, 200), Image.ANTIALIAS) images.append([fileImageImport, width, height]) photo = ImageTk.PhotoImage(fileImageImport) fileImage = Label(rightComponentFrame, image=photo, bg=bg) fileImage.image = photo fileImage.pack(padx=(0, 100), anchor="e") refresh(webScrapingWindow) imageCounter+=1 webScrapingRightPane[webScrapingPage] = rightComponentFrame # perform image scraping if enabled in options if options["Reverse Image Search (B)"].get() == True and not track.stop: if not performSearch(initialCounter, imageCounter): imageCounter, images, track = reverseImageSearch(link, headers, imageCounter, images, track, options) except UnidentifiedImageError: pass return imageCounter, images, webScrapingLeftPane, webScrapingRightPane
def reverseImageSearch(link, headers, imageCounter, images, track, options): if track.browser == 'NA': try: seleniumOptions = webdriver.FirefoxOptions() if options['Hide Selenium Browser (B)'].get(): seleniumOptions.add_argument('--headless') browser = webdriver.Firefox( executable_path=resource_path('geckodriver.exe'), options=seleniumOptions, service_log_path='nul') track.browser = browser except: pass url = "https://images.google.com/searchbyimage?image_url=" + link if "https://" in link: link = link.replace("https://", '') elif "http://" in link: link = link.replace("http://", '') if track.browser != 'NA': try: browser = track.browser browser.set_window_position(0, 0) browser.set_window_size(700, 500) browser.get(url) text = browser.find_elements_by_class_name("O1id0e") if len(text) > 0: text = text[0] sizes = [] # append all sizes to list (in case of non-english language) imageLinks = text.find_elements_by_class_name('gl') if len(imageLinks) > 0: for image in imageLinks: text = image.text.replace('-', '').strip() sizes.append(text) # check for popups time.sleep(1) popups = browser.find_elements_by_xpath("//iframe") if len(popups) > 0: for popup in popups: link = popup.get_attribute('src') if 'consent.google.com/' in popup.get_attribute( 'src'): link = popup.get_attribute('src').replace( "consent.google.com/", "consent.google.com") break # switch frames browser.switch_to.frame( browser.find_element_by_xpath("//iframe[@src='" + link + "']")) browser.find_element_by_xpath( "//form[@class='A28uDc']").click() # return to original frame browser.switch_to.default_content() # search by the largest size browser.find_element_by_link_text(sizes[len(sizes) - 1]).click() for i in range(2): displayimages = browser.find_elements_by_class_name( "rg_i.Q4LuWd") # make sure images have actually appeared if len(displayimages) > 0: displayimages[i].click() time.sleep(0.5) counter = 0 subImages = browser.find_elements_by_xpath( "//img[@class='n3VNCb']") # wait for image to load with 1/2 second increments while subImages == None and counter < int( options["Image Load Wait Time (I)"].get()): time.sleep(0.5) subImages = browser.find_elements_by_xpath( "//img[@class='n3VNCb']") counter += 0.5 counter = 0 for image in subImages: while 'data:image' in image.get_attribute( 'src') and counter < int(options[ "Image Load Wait Time (I)"].get()): time.sleep(0.5) counter += 0.5 if 'data:image' not in image.get_attribute( 'src'): browser.get(image.get_attribute('src')) # avoid duplicates if browser.current_url not in track.URLList: track.URLList.append( browser.current_url) try: with open( resource_path( 'Temp/' + str(imageCounter) + '.jpg'), "wb") as file: file.write( requests.get( browser.current_url, headers=headers). content) fileImageImport = Image.open( resource_path( 'Temp/' + str(imageCounter) + '.jpg')) imageCounter += 1 # check image parameters width, height = fileImageImport.size fileImageImport = fileImageImport.resize( (200, 200), Image.ANTIALIAS) images.append([ fileImageImport, width, height ]) if options["Stop Search After Conditions (B)"].get( ) and width >= int( options[ "Stop Search After Finding Image of Resolution (S)"] .get().split('x')[0] ) and height >= int(options[ "Stop Search After Finding Image of Resolution (S)"] .get().split( 'x')[1]): track.stop = True except: pass break browser.minimize_window() except: pass return imageCounter, images, track
def fileSelect(options, imageCounter, CONFIG_FILE, window): directories = filedialog.askopenfilenames(title="Select File") webScrapingWindow = False webScrapingPage = 0 if directories != '': # delete previous web scraping window from previous session if type(window) != bool: window.destroy() imageSelections = [] finalTitles = [] finalResults = [] characters = 0 images = [] thumbnails = [] # create webscraping window on top left corner webScrapingWindow = Toplevel() webScrapingWindow.title("Web Scraping Display") webScrapingWindow.configure(bg=bg) webScrapingWindow.geometry("1000x300+0+0") webScrapingWindow.iconbitmap(resource_path('favicon.ico')) # component for search label and page indicator labelFrame = tk.Frame(webScrapingWindow, bg=bg) labelFrame.pack(fill=X, pady=(10, 10)) searchFrame = tk.Frame(labelFrame, bg=bg) searchFrame.pack(side="left") pageFrame = tk.Frame(labelFrame, bg=bg) pageFrame.pack(side="right", pady=(20, 0)) componentFrame = tk.Frame(webScrapingWindow, bg=bg) componentFrame.pack(fill=X, pady=(10, 0)) rerenderControls(pageFrame, 0) # dictionary to store web scraping window values webScrapingLeftPane = {} webScrapingRightPane = {} webScrapingLinks = {} track = '' browser = '' for directory in directories: filename = os.path.basename(directory) directory = os.path.dirname(directory) if not checkValidity(filename): extension = filename[filename.rfind("."):] messagebox.showinfo("Error", extension + " is not a supported format") if str(directory) + "/" + str(filename) == str( directories[len(directories) - 1]): webScrapingWindow.destroy() audio = False if hasattr(track, 'browser'): browser = track.browser informalTagDict = '' # handle FLAC file if filename.endswith('.flac') and type( checkFileValidity(filename, directory, "FLAC")) != str: # handle naming preferences, tag settings, and replay gain audio, filename, informalTagDict, thumbnails, options = initiateFLAC( filename, directory, thumbnails, options) if type(audio) != bool: track = FLAC_Track(audio, options, informalTagDict, browser) # handle AIFF file elif filename.endswith('.aiff') and type( checkFileValidity(filename, directory, "AIFF")) != str: audio, filename, informalTagDict, thumbnails, options = initiateAIFF( filename, directory, thumbnails, options) if type(audio) != bool: track = ID3_Track(audio, options, informalTagDict, browser) # handle MP3 file elif filename.endswith('mp3') and type( checkFileValidity(filename, directory, "MP3")) != str: audio, filename, informalTagDict, thumbnails, options = initiateMP3( filename, directory, thumbnails, options) if type(audio) != bool: track = ID3_Track(audio, options, informalTagDict, browser) # handle OGG file elif filename.endswith('.ogg') and type( checkFileValidity(filename, directory, "OGG")) != str: audio, filename, informalTagDict, thumbnails, options = initiateOGG( filename, directory, thumbnails, options) if type(audio) != bool: track = Vorbis_Track(audio, options, informalTagDict, browser) # handle WAV file elif filename.endswith('.wav') and type( checkFileValidity(filename, directory, "WAV")) != str: audio, filename, informalTagDict, thumbnails, options = initiateWAVE( filename, directory, thumbnails, options) if type(audio) != bool: track = ID3_Track(audio, options, informalTagDict, browser) # handle AAC and ALAC files elif filename.endswith('.m4a') and type( checkFileValidity(filename, directory, "M4A")) != str: audio, filename, informalTagDict, thumbnails, options = initiateM4A( filename, directory, thumbnails, options) if type(audio) != bool: track = M4A_Track(audio, options, informalTagDict, browser) # search web for tags if type(audio) != bool: reportTitle, reportResults, webScrapingWindow, characters, imageCounter, imageSelection, images, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage, searchFrame, pageFrame, componentFrame = scrapeWeb( track, audio, filename, webScrapingWindow, characters, options, imageCounter, images, informalTagDict, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage, labelFrame, searchFrame, pageFrame, componentFrame) finalTitles.append(reportTitle) finalResults.append(reportResults) imageSelections.append(imageSelection) # close selenium browser if it exists if track != '' and track.browser != 'NA': track.browser.quit() # enable controls in web scraping window if type(webScrapingWindow) != bool: enableControls(searchFrame, pageFrame, webScrapingLeftPane, webScrapingRightPane, webScrapingLinks, webScrapingPage, componentFrame) handleFinalReport(finalTitles, finalResults, characters, imageCounter, imageSelections, webScrapingWindow, thumbnails, options, CONFIG_FILE) return webScrapingWindow, webScrapingPage
def handleFinalReport(finalTitles, finalResults, characters, imageCounter, imageSelections, webScrapingWindow, thumbnails, options, CONFIG_FILE): global currentPage currentPage = 1 finalReportWindow = tk.Toplevel() finalReportWindow.title("Final Report") finalReportWindow.configure(bg=bg) ws = finalReportWindow.winfo_screenwidth() # width of the screen hs = finalReportWindow.winfo_screenheight() # height of the screen y = (hs / 2) - (682 / 2) x = (ws / 2) - (550 / 2) finalReportWindow.geometry('%dx%d+%d+%d' % (550, 620, x, y)) if characters > 40: x = (ws / 2) - ((550 + (characters * 1.5)) / 2) finalReportWindow.geometry('%dx%d+%d+%d' % (550 + (characters * 1.5), 620, x, y)) tk.Label(finalReportWindow, text="Final Report", font=("Proxima Nova Rg", 13), fg="white", bg=bg).pack(side="top", pady=(30, 15)) # frame for title titleFrame = tk.Frame(finalReportWindow, bg=bg) titleFrame.pack(side="top", anchor="n") tk.Label(titleFrame, text=finalTitles[0] + "\n", font=("Proxima Nova Rg", 11), fg="white", bg=bg, justify="left", bd=-10, anchor="w").pack(side="top", anchor="w") # frame for report contents contentFrame = tk.Frame(finalReportWindow, bg=bg) contentFrame.pack(side="top", anchor="center") # remove leading newline character tk.Label(contentFrame, text=finalResults[0].lstrip() + '\n', font=("Proxima Nova Rg", 11), fg="white", bg=bg, justify="left", bd=-10, anchor="w").pack(anchor="center") # frame for image imageFrame = tk.Frame(finalReportWindow, bg=bg) imageFrame.pack(side="top", anchor="n") renderImage(imageFrame, imageSelections, imageCounter, thumbnails, 0) # navigation buttons navigationButtons = tk.Frame(finalReportWindow, bg=bg) navigationButtons.pack(pady=(10, 10)) rightNavigationButton = tk.Button( navigationButtons, text=" > ", font=("Proxima Nova Rg", 11), fg="white", bg=bg, anchor="e", width=2, command=lambda: navigateRight( leftNavigationButton, rightNavigationButton, titleFrame, contentFrame, imageFrame, finalTitles, finalResults, imageSelections, imageCounter, thumbnails, pageIndicator)) rightNavigationButton.pack(side="right") if len(finalResults) == 1: rightNavigationButton.config(state=DISABLED) pageIndicator = tk.Label(navigationButtons, text=str(currentPage) + "/" + str(len(finalResults)), font=("Proxima Nova Rg", 11), fg="white", bg=bg, anchor='e') pageIndicator.pack(side="right", padx=(10, 10)) leftNavigationButton = tk.Button( navigationButtons, text=" < ", state=DISABLED, font=("Proxima Nova Rg", 11), fg="white", bg=bg, anchor="e", width=2, command=lambda: navigateLeft(leftNavigationButton, rightNavigationButton, titleFrame, contentFrame, imageFrame, finalTitles, finalResults, imageSelections, imageCounter, thumbnails, pageIndicator)) leftNavigationButton.pack(side="right") # load button and checkbox tk.Button(finalReportWindow, text='OK', command=lambda: completeSearch(finalReportWindow, webScrapingWindow, options), font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side=TOP, pady=(35, 15)) closeWindowButtonFrame = tk.Frame(finalReportWindow, bg=bg) closeWindowButtonFrame.pack() tk.Checkbutton(closeWindowButtonFrame, var=options["Close Scraping Window (B)"], activebackground=bg, command=lambda: closeScrapingWindowSelection(CONFIG_FILE), bg=bg).pack(side="left", pady=(0, 10)) tk.Label(closeWindowButtonFrame, text="Close scraping window", font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side="left", pady=(0, 10)) finalReportWindow.protocol( 'WM_DELETE_WINDOW', lambda: completeSearch(finalReportWindow, webScrapingWindow, options)) finalReportWindow.iconbitmap(resource_path('favicon.ico')) finalReportWindow.lift() finalReportWindow.wait_window()
def readValuesFromConfig(CONFIG_FILE): config_file = open(CONFIG_FILE, 'r').read() terms = [ "Subdirectories (B)", "Close Scraping Window (B)", "First Default Directory (S)", "Second Default Directory (S)", "Copy Directory Contents (B)", "Scrape Junodownload (B)", "Scrape Beatport (B)", 'Scrape Discogs (B)', "Extract Image from Website (B)", "Limit Number of Matches per Site (B)", "Match Limit (I)", "Reverse Image Search (B)", "Delete Stored Images (B)", "Image Load Wait Time (I)", "Number of Images Per Page (I)", "Stop Search After Conditions (B)", "Stop Search After Finding Image of Resolution (S)", "Hide Selenium Browser (B)", "Scan Filename and Tags (B)", "Check for Numbering Prefix (B)", "Check for Extraneous Hyphens (B)", "Check for Underscores (B)", "Check for Capitalization (B)", "Always Capitalize (L)", "Never Capitalize (L)", "Audio naming format (S)", "Selected Tags (L)", "Delete Unselected Tags (B)" ] options = {} for term in terms: if term in config_file: # boolean if (term[len(term) - 2:len(term) - 1]) == 'B': try: options[term] = tk.BooleanVar(value=config_file[ config_file.index(term) + len(term) + 1:config_file.find('\n', config_file.index(term) + len(term))]) except: os.remove(resource_path('Settings.txt')) CONFIG_FILE = createConfigFile("F") readValuesFromConfig(CONFIG_FILE) # string elif (term[len(term) - 2:len(term) - 1]) == 'S': try: options[term] = tk.StringVar( value=config_file[config_file.index(term) + len(term) + 1:config_file.index( '\n', config_file.index(term) + len(term))]) except: os.remove(resource_path('Settings.txt')) CONFIG_FILE = createConfigFile("F") readValuesFromConfig(CONFIG_FILE) # integer elif (term[len(term) - 2:len(term) - 1]) == 'I': try: options[term] = tk.IntVar( value=config_file[config_file.index(term) + len(term) + 1:config_file.index( '\n', config_file.index(term) + len(term))]) except: os.remove(resource_path('Settings.txt')) CONFIG_FILE = createConfigFile("F") readValuesFromConfig(CONFIG_FILE) # list elif (term[len(term) - 2:len(term) - 1]) == 'L': try: if (config_file[config_file.index(term) + len(term) + 1:config_file. index('\n', config_file.index(term) + len(term))].split(', ')) == ['']: options[term] = [] else: options[term] = config_file[ config_file.index(term) + len(term) + 1:config_file. index('\n', config_file.index(term) + len(term))].split(', ') except: os.remove(resource_path('Settings.txt')) CONFIG_FILE = createConfigFile("F") readValuesFromConfig(CONFIG_FILE) else: os.remove(resource_path('Settings.txt')) CONFIG_FILE = createConfigFile("F") readValuesFromConfig(CONFIG_FILE) return options
def handleDiscrepancy(original, new, index, type, options): global change, word, capitalize, uncapitalize word = '' popup = tk.Toplevel() popup.title("Potential Typo - " + type) ws = popup.winfo_screenwidth() # width of the screen hs = popup.winfo_screenheight() # height of the screen x = (ws / 2) - (550 / 2) y = (hs / 2) - (330 / 2) popup.geometry('%dx%d+%d+%d' % (550, 300, x, y)) if type == "Capitalization": x = (ws / 2) - (550 / 2) popup.geometry('%dx%d+%d+%d' % (650, 300, x, y)) popup.configure(bg=bg) originalName = ' '.join(original) newName = ' '.join(new) if max(len(originalName), len(newName)) > 50 or len(new[index]) > 15: if max(len(originalName), len(newName)) > 50 and len(new[index]) > 15: value = max(((550 + (max(len(originalName), len(newName)) * 1.5))), ((550 + (len(new[index]) * 6)))) x = (ws / 2) - (value / 2) popup.geometry('%dx%d+%d+%d' % (value, 300, x, y)) if type == "Capitalization": value = max( ((650 + (max(len(originalName), len(newName)) * 1.5))), ((650 + (len(new[index]) * 6)))) x = (ws / 2) - (value / 2) popup.geometry('%dx%d+%d+%d' % (value, 300, x, y)) elif max(len(originalName), len(newName)) > 50: x = (ws / 2) - ((550 + (max(len(originalName), len(newName)) * 1.5)) / 2) popup.geometry( '%dx%d+%d+%d' % (550 + (max(len(originalName), len(newName)) * 1.5), 300, x, y)) if type == "Capitalization": x = (ws / 2) - ( (650 + (max(len(originalName), len(newName)) * 1.5)) / 2) popup.geometry( '%dx%d+%d+%d' % (650 + (max(len(originalName), len(newName)) * 1.5), 300, x, y)) else: x = (ws / 2) - ((550 + (len(new[index]) * 6)) / 2) popup.geometry('%dx%d+%d+%d' % (550 + (len(new[index]) * 6), 300, x, y)) if type == "Capitalization": x = (ws / 2) - ((650 + (len(new[index]) * 6)) / 2) popup.geometry('%dx%d+%d+%d' % (650 + (len(new[index]) * 6), 300, x, y)) tk.Label( popup, text= "A potential typo/error was found. \nAccept or reject the proposed filename\n", font=("Proxima Nova Rg", 14), fg="white", bg=bg).pack(pady=(20, 10)) # pack a label for each individual word in the current filename tk.Label(popup, text="Current filename", font=("Proxima Nova Rg", 12), fg="white", bg=bg).pack() currentFilenameContainer = tk.Label(popup, text=originalName, justify="left", font=("Proxima Nova Rg", 11), fg="white", bg=bg) currentFilenameContainer.pack(pady=(0, 25)) beforeHighlight = '' for i in range(0, index): beforeHighlight += original[i] + ' ' beforeHighlight.strip() highlight, word = new[index], new[index] afterHighlight = '' for i in range(index + 1, len(original)): afterHighlight += original[i] + ' ' afterHighlight.strip() # pack a label for each individual word in the proposed filename newFilenameContainer = tk.Label(popup, justify="left", fg="white", bg=bg) newFilenameContainer.pack(pady=(0, 10)) tk.Label(newFilenameContainer, text=beforeHighlight, borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side="left") tk.Label(newFilenameContainer, text=highlight, borderwidth=-2, font=("Proxima Nova Rg", 11), fg="black", bg="yellow").pack(side="left") tk.Label(newFilenameContainer, text=afterHighlight, borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg).pack(side="left") buttons = tk.Frame(popup, bg=bg) buttons.pack(side="top") tk.Button(buttons, text='Accept', command=lambda: setChange(popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(35, 10), padx=(10, 30), side="left") tk.Button(buttons, text='Reject', command=lambda: closePopup(popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(35, 10), padx=(30, 10), side="left") if type == "Capitalization": tk.Button(buttons, text="Always Accept " + "(" + word + ")", width=15 + math.ceil(len(word) / 1.5), command=lambda: addCapitalizedList(word, popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(35, 10), padx=(30, 10), side="left") tk.Button(buttons, text="Always Reject " + "(" + word.lower() + ")", width=15 + math.ceil(len(word) / 1.5), command=lambda: addUncapitalizedList(word, popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(35, 10), padx=(30, 10), side="left") popup.iconbitmap(resource_path('favicon.ico')) popup.wait_window() if capitalize: options["Always Capitalize (L)"].append(word.capitalize()) elif uncapitalize: options["Never Capitalize (L)"].append(word.lower()) capitalize = False uncapitalize = False word = '' else: popup.iconbitmap(resource_path('favicon.ico')) popup.protocol("WM_DELETE_WINDOW", lambda: popup.destroy()) popup.wait_window() if change: originalName = '' for i in range(0, index + 1): originalName += new[i] + ' ' for i in range(index + 1, len(original)): originalName += original[i] + ' ' originalName = originalName.strip() return originalName, options, True return originalName, options, False
def handleTypo(artist, newArtist, title, newTitle, type, options): global change, word, capitalize, uncapitalize popup = tk.Toplevel() popup.title("Potential Typo - " + type) ws = popup.winfo_screenwidth() # width of the screen hs = popup.winfo_screenheight() # height of the screen x = (ws / 2) - (450 / 2) y = (hs / 2) - (352 / 2) popup.geometry('%dx%d+%d+%d' % (450, 320, x, y)) if type == "Capitalization": x = (ws / 2) - (550 / 2) popup.geometry('%dx%d+%d+%d' % (550, 320, x, y)) popup.configure(bg=bg) if len(str(artist) + " - " + str(title)) > 50: x = (ws / 2) - ((450 + (len(str(artist) + " - " + str(title)) * 3)) / 2) popup.geometry( '%dx%d+%d+%d' % (450 + (len(str(artist) + " - " + str(title)) * 3), 320, x, y)) if type == "Capitalization": x = (ws / 2) - ( (550 + (len(str(artist) + " - " + str(title)) * 1.5)) / 2) popup.geometry( '%dx%d+%d+%d' % (550 + (len(str(artist) + " - " + str(title)) * 1.5), 320, x, y)) tk.Label( popup, text= "A potential typo/error was found. \nAccept or reject the proposed filename\n", font=("Proxima Nova Rg", 14), fg="white", bg=bg).pack(pady=(20, 10)) # pack a label for each individual word in the current filename tk.Label(popup, text="Current filename", font=("Proxima Nova Rg", 12), fg="white", bg=bg).pack() currentFilename = str(artist).split(' ') currentFilename.append('-') currentFilename += str(title).split(' ') currentFilenameContainer = tk.Label(popup, justify="left", fg="white", bg=bg) currentFilenameContainer.pack(pady=(0, 25)) currentFilenameDict = {} for i in range(len(currentFilename)): currentFilenameDict[i] = tk.Label(currentFilenameContainer, text=currentFilename[i], borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg) currentFilenameDict[i].pack(side="left") if i != len(currentFilename) - 1: tk.Label(currentFilenameContainer, text='', borderwidth=-2, fg="white", bg=bg).pack(side="left") # pack a label for each individual word in the proposed filename tk.Label(popup, text="Proposed filename", font=("Proxima Nova Rg", 12), fg="white", bg=bg).pack(pady=(10, 0)) newFilename = str(newArtist).split(' ') newFilename.append('-') newFilename += str(newTitle).split(' ') newFilenameContainer = tk.Label(popup, justify="left", fg="white", bg=bg) newFilenameContainer.pack(pady=(0, 10)) newFilenameDict = {} for i in range(len(newFilename)): newFilenameDict[i] = tk.Label(newFilenameContainer, text=str(newFilename[i].replace( '*hyphen*', ' ')), borderwidth=-2, font=("Proxima Nova Rg", 11), fg="white", bg=bg) newFilenameDict[i].pack(side="left") if i != len(newFilename) - 1: tk.Label(newFilenameContainer, text='', borderwidth=-2, fg="white", bg=bg).pack(side="left") # highlight word if it does not match with the current filename; only highlight the first mismatched word if type == 'Hyphen': if len(currentFilename) == len( newFilename) and currentFilename[i] != newFilename[i]: currentFilenameDict[i].configure(fg="black", bg="yellow") newFilenameDict[i].configure(fg="black", bg="yellow") else: if len(currentFilename) == len(newFilename) and currentFilename[ i] != newFilename[i] and word == '': word = str(newFilenameDict[i]["text"]) currentFilenameDict[i].configure(fg="black", bg="yellow") newFilenameDict[i].configure(fg="black", bg="yellow") buttons = tk.Frame(popup, bg=bg) buttons.pack(side="top") tk.Button(buttons, text='Accept', command=lambda: setChange(popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(25, 10), padx=(10, 30), side="left") tk.Button(buttons, text='Reject', command=lambda: closePopup(popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(25, 10), padx=(30, 10), side="left") if type == "Capitalization": tk.Button(buttons, text="Always Accept " + "(" + word + ")", command=lambda: addCapitalizedList(word, popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(25, 10), padx=(30, 10), side="left") tk.Button(buttons, text="Always Reject " + "(" + word.lower() + ")", command=lambda: addUncapitalizedList(word, popup), font=("Proxima Nova Rg", 11), fg="white", bg=secondary_bg).pack(pady=(25, 10), padx=(30, 10), side="left") popup.iconbitmap(resource_path('favicon.ico')) popup.wait_window() if capitalize: options["Always Capitalize (L)"].append(word.capitalize()) elif uncapitalize: options["Never Capitalize (L)"].append(word.lower()) capitalize = False uncapitalize = False word = '' else: popup.iconbitmap(resource_path('favicon.ico')) popup.protocol("WM_DELETE_WINDOW", lambda: popup.destroy()) popup.wait_window() if change: artist = newArtist title = newTitle return artist, title, options, True return artist, title, options, False