I am trying to display a popup window that will show the results from an API using PySimple GUI call after the user has selected an item, but nothing is showing when the button is being clicked.
import PySimpleGUI as sg
# import PySimpleGUIQt as sg
import os.path
import PIL.Image
import io
#import imutils
import requests
import base64
import json
import base64
from detect_face_video import main
"""
"""
plate='f'
def convert_to_bytes(file_or_bytes, resize=None):
'''
Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
Turns into PNG format in the process so that can be displayed by tkinter
:param file_or_bytes: either a string filename or a bytes base64 image object
:type file_or_bytes: (Union[str, bytes])
:param resize: optional new size
:type resize: (Tuple[int, int] or None)
:return: (bytes) a byte-string object
:rtype: (bytes)
'''
if isinstance(file_or_bytes, str):
img = PIL.Image.open(file_or_bytes)
else:
try:
img = PIL.Image.open(io.BytesIO(base64.b64decode(file_or_bytes)))
except Exception as e:
dataBytesIO = io.BytesIO(file_or_bytes)
img = PIL.Image.open(dataBytesIO)
cur_width, cur_height = img.size
if resize:
new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS)
with io.BytesIO() as bio:
img.save(bio, format="PNG")
del img
return bio.getvalue()
def update_plate(filename):
SECRET_KEY = 'sk_ed3d203bf4c9a7c2910ec0c0'
with open(filename, 'rb') as image_file:
img_base64 = base64.b64encode(image_file.read())
url = 'https://api.openalpr.com/v3/recognize_bytes?recognize_vehicle=1&country=us&secret_key=%s' % (SECRET_KEY)
r = requests.post(url, data = img_base64)
try:
global plate
plate=r.json()['results'][0]['plate'],
global Brand
Brand= r.json()['results'][0]['vehicle']['make_model'][0]['name'],
global Color
Color= r.json()['results'][0]['vehicle']['color'][0]['name'],
print(plate)
except:
print ('error')
# --------------------------------- Define Layout ---------------------------------
# First the window layout...2 columns
sg.theme('Dark Blue 3')
left_col = [[sg.Text('Folder'), sg.In(size=(25,1), enable_events=True ,key='-FOLDER-'), sg.FolderBrowse()],
[sg.Listbox(values=[], enable_events=True, size=(40,20),key='-FILE LIST-')],
[sg.Text('Resize to'), sg.In(key='-W-', size=(5,1)), sg.In(key='-H-', size=(5,1))],
[sg.Button("Resize", button_color=("white", "blue"), size=(6, 1))]]
# For now will only show the name of the file that was chosen
images_col = [[sg.Text('You choose from the list:')],
[sg.Text(size=(40,1), key='-TOUT-')],
[sg.Image(key='-IMAGE-')]]
# ----- Full layout -----
layout = [[sg.Column(left_col, element_justification='c'), sg.VSeperator(),sg.Column(images_col, element_justification='c')]]
# --------------------------------- Create Window ---------------------------------
window = sg.Window('Multiple Format Image Viewer', layout,resizable=True)
# ----- Run the Event Loop -----
# --------------------------------- Event Loop ---------------------------------
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == '-FOLDER-': # Folder name was filled in, make a list of files in the folder
folder = values['-FOLDER-']
try:
file_list = os.listdir(folder) # get list of files in folder
except:
file_list = []
fnames = [f for f in file_list if os.path.isfile(
os.path.join(folder, f)) and f.lower().endswith((".png", ".jpg", "jpeg", ".tiff", ".bmp"))]
window['-FILE LIST-'].update(fnames)
if event == 'Resize':
window['-IMAGE-'].update(data=convert_to_bytes(filename, resize=new_size))
elif event == '-FILE LIST-': # A file was chosen from the listbox
try:
filename = os.path.join(values['-FOLDER-'], values['-FILE LIST-'][0])
window['-TOUT-'].update(filename)
if values['-W-'] and values['-H-']:
new_size = int(values['-W-']), int(values['-H-'])
else:
new_size = None
window['-IMAGE-'].update(data=convert_to_bytes(filename, resize=new_size))
main(filename)
update_plate(filename)
print(plate)
except Exception as E:
print(f'** Error {E} **')
pass # something weird happened making the full filename
# --------------------------------- Close & Exit ---------------------------------
window.close()
Setting keep on top in the Popup call created the window on top for me. Just add
sg.Popup("license plate" , plate , keep_on_top=True)
However, if you click on the window behind, because it also has keep on top set, it will cover your popup.
Related
I want to read a image from api, but I am getting a error TypeError: 'module' object is not callable. I am trying to make a random meme generator
import PySimpleGUI as sg
from PIL import Image
import requests, json
cutURL = 'https://meme-api-python.herokuapp.com/gimme'
imageURL = json.loads(requests.get(cutURL).content)["url"]
img = Image(requests.get(imageURL).content)
img_box = sg.Image(img)
window = sg.Window('', [[img_box]])
while True:
event, values = window.read()
if event is None:
break
window.close()
Here is the response of the api
postLink "https://redd.it/yyjl2e"
subreddit "dankmemes"
title "Everything's fixed"
url "https://i.redd.it/put9bi0vjp0a1.jpg"
I tried using python simple gui module, IS there alternative way to make a random meme generator.
PIL.Image is a module, you can not call it by Image(...), maybe you need call it by Image.open(...). At the same, tkinter/PySimpleGUI cannot handle JPG image, so conversion to PNG image is required.
from io import BytesIO
import PySimpleGUI as sg
from PIL import Image
import requests, json
def image_to_data(im):
"""
Image object to bytes object.
: Parameters
im - Image object
: Return
bytes object.
"""
with BytesIO() as output:
im.save(output, format="PNG")
data = output.getvalue()
return data
cutURL = 'https://meme-api-python.herokuapp.com/gimme'
imageURL = json.loads(requests.get(cutURL).content)["url"]
data = requests.get(imageURL).content
stream = BytesIO(data)
img = Image.open(stream)
img_box = sg.Image(image_to_data(img))
window = sg.Window('', [[img_box]], finalize=True)
# Check if the size of the window is greater than the screen
w1, h1 = window.size
w2, h2 = sg.Window.get_screen_size()
if w1>w2 or h1>h2:
window.move(0, 0)
while True:
event, values = window.read()
if event is None:
break
window.close()
You need to use Image.open(...) - Image is a module, not a class. You can find a tutorial in the official PIL documentation.
You may need to put the response content in a BytesIO object before you can use Image.open on it. BytesIO is a file-like object that exists only in memory. Most functions like Image.open that expect a file-like object will also accept BytesIO and StringIO (the text equivalent) objects.
Example:
from io import BytesIO
def get_image(url):
data = BytesIO(requests.get(url).content)
return Image.open(data)
I would do it with tk its simple and fast
def window():
root = tk.Tk()
panel = Label(root)
panel.pack()
img = None
def updata():
response = requests.get(https://meme-api-python.herokuapp.com/gimme)
img = Image.open(BytesIO(response.content))
img = img.resize((640, 480), Image.ANTIALIAS) #custom resolution
img = ImageTk.PhotoImage(img)
panel.config(image=img)
panel.image = img
root.update_idletasks()
root.after(30, updata)
updata()
root.mainloop()
I am creating a piece of software for my organisation which I recently started, and I am using the Tkinter module in Python to create my software. The software is similar to how an operating system works, but it isn't an operating system, and it runs like a normal program on your desktop. In the software, there are numerous applications, like a word-processor (more on that later), a spreadsheet editor, etc.
The first application I am creating is a word processor called Wordee, and I've based it on a style that mirrors Microsoft Notepad. I want the user to click a button and the word-processor opens code from a class in another file in the same directory. This class is the code for the word processor.
I have written that code, but it always opens the word processor first and then when you close the word processor, the window that you should access the word processor from.
Here is the code which I am currently developing - everything that I have written was where I got up to when I noticed the problem:
from tkinter import *
import time
import os
import wordProcessorExample as wPE
window = Tk()
window.title("Brainwave One")
def get_datetime():
timeVariable = time.strftime("%I:%M %p, %A %d %B %Y")
date_time.config(text=timeVariable)
date_time.after(200,get_datetime)
def wordee():
print(wPE.Wordee)
date_time = Label(window,font=("Calibri",15))
date_time.grid(row=0,column=0)
title = Label(window,text="Brainwave One",font=("Calibri",40))
title.place(relx=0.5,rely=0.05,anchor="center")
title = Label(window,text="From The Brainwave Incorporation",font=("Calibri",13))
title.place(relx=0.5,rely=0.083,anchor="center")
wordee = Button(window,text="Wordee",font=("Calibri",23),command=wordee)
wordee.place(relx=0.25,rely=0.1875,anchor="center")
get_datetime()
window.mainloop()
Here is the other file that I am accessing the class for the word processor from:
import tkinter
import os
from tkinter import *
from tkinter.messagebox import *
from tkinter.filedialog import *
class Wordee:
__root = Tk()
# default window width and height
__thisWidth = 300
__thisHeight = 300
__thisTextArea = Text(__root)
__thisMenuBar = Menu(__root)
__thisFileMenu = Menu(__thisMenuBar, tearoff=0)
__thisEditMenu = Menu(__thisMenuBar, tearoff=0)
__thisHelpMenu = Menu(__thisMenuBar, tearoff=0)
# To add scrollbar
__thisScrollBar = Scrollbar(__thisTextArea)
__file = None
def __init__(self,**kwargs):
# Set icon
try:
self.__root.wm_iconbitmap("Wordee.ico")
except:
pass
# Set window size (the default is 300x300)
try:
self.__thisWidth = kwargs['width']
except KeyError:
pass
try:
self.__thisHeight = kwargs['height']
except KeyError:
pass
# Set the window text
self.__root.title("Untitled - Wordee")
# Center the window
screenWidth = self.__root.winfo_screenwidth()
screenHeight = self.__root.winfo_screenheight()
# For left-align
left = (screenWidth / 2) - (self.__thisWidth / 2)
# For right-align
top = (screenHeight / 2) - (self.__thisHeight /2)
# For top and bottom
self.__root.geometry('%dx%d+%d+%d' % (self.__thisWidth,
self.__thisHeight,
left, top))
# To make the textarea auto resizable
self.__root.grid_rowconfigure(0, weight=1)
self.__root.grid_columnconfigure(0, weight=1)
# Add controls (widget)
self.__thisTextArea.grid(sticky = N + E + S + W)
# To open new file
self.__thisFileMenu.add_command(label="New",
command=self.__newFile)
# To open a already existing file
self.__thisFileMenu.add_command(label="Open",
command=self.__openFile)
# To save current file
self.__thisFileMenu.add_command(label="Save",
command=self.__saveFile)
# To create a line in the dialog
self.__thisFileMenu.add_separator()
self.__thisFileMenu.add_command(label="Exit",
command=self.__quitApplication)
self.__thisMenuBar.add_cascade(label="File",
menu=self.__thisFileMenu)
# To give a feature of cut
self.__thisEditMenu.add_command(label="Cut",
command=self.__cut)
# to give a feature of copy
self.__thisEditMenu.add_command(label="Copy",
command=self.__copy)
# To give a feature of paste
self.__thisEditMenu.add_command(label="Paste",
command=self.__paste)
# To give a feature of editing
self.__thisMenuBar.add_cascade(label="Edit",
menu=self.__thisEditMenu)
# To create a feature of description of the notepad
self.__thisHelpMenu.add_command(label="About Wordee",
command=self.__showAbout)
self.__thisMenuBar.add_cascade(label="Help",
menu=self.__thisHelpMenu)
self.__root.config(menu=self.__thisMenuBar)
self.__thisScrollBar.pack(side=RIGHT,fill=Y)
# Scrollbar will adjust automatically according to the content
self.__thisScrollBar.config(command=self.__thisTextArea.yview)
self.__thisTextArea.config(yscrollcommand=self.__thisScrollBar.set)
def __quitApplication(self):
self.__root.destroy()
# exit()
def __showAbout(self):
showinfo("Notepad","Mrinal Verma")
def __openFile(self):
self.__file = askopenfilename(defaultextension=".wde",
filetypes=[("All Files","*.*"),
("Text Documents","*.wde")])
if self.__file == "":
# no file to open
self.__file = None
else:
# Try to open the file
# set the window title
self.__root.title(os.path.basename(self.__file) + " - Wordee")
self.__thisTextArea.delete(1.0,END)
file = open(self.__file,"r")
self.__thisTextArea.insert(1.0,file.read())
file.close()
def __newFile(self):
self.__root.title("Untitled - Wordee")
self.__file = None
self.__thisTextArea.delete(1.0,END)
def __saveFile(self):
if self.__file == None:
# Save as new file
self.__file = asksaveasfilename(initialfile='Untitled.wde',
defaultextension=".wde",
filetypes=[("All Files","*.*"),
("Text Documents","*.wde")])
if self.__file == "":
self.__file = None
else:
# Try to save the file
file = open(self.__file,"w")
file.write(self.__thisTextArea.get(1.0,END))
file.close()
# Change the window title
self.__root.title(os.path.basename(self.__file) + " - Wordee")
else:
file = open(self.__file,"w")
file.write(self.__thisTextArea.get(1.0,END))
file.close()
def __cut(self):
self.__thisTextArea.event_generate("<<Cut>>")
def __copy(self):
self.__thisTextArea.event_generate("<<Copy>>")
def __paste(self):
self.__thisTextArea.event_generate("<<Paste>>")
def run(self):
# Run main application
self.__root.mainloop()
# Run main application
Wordee = Wordee(width=600,height=400)
Wordee.run()
I have this python script to work with Telebot to watermark images in Telegram and then send back the watermarked image in the bot chat.
I have obtained this from Github and wish to change it but I'm failing somehow.
Current flow
Send image to watermark bot
Watermark bot will download the image, add the watermark in both Black and White
Watermark bot will send back two images in the chat, one of each color
Desired flow
Just one color (White) be sent back.
CODE 1
from PIL import Image, ImageFont, ImageDraw, ImageEnhance
import hashlib
import piexif
import config
def getting_ready(path):
fname = md5(path) + '.jpg'
image = Image.open(path).convert('RGB')
try:
exif_dict = piexif.load(image.info['exif'])
orientation = exif_dict['0th'][274]
except KeyError:
orientation = None
rotate_values = {3: 180, 6: 270, 8: 90}
if orientation in rotate_values:
image = image.rotate(rotate_values[orientation], expand=True)
for color in ['black', 'white']:
watermark(image, fname, color)
return fname
def watermark(img, new_fname, color):
text = config.WATERMARK
wm = Image.new('RGBA', img.size, (0, 0, 0, 0))
fontsize = img.size[1] // 100 * config.FONT_SIZE
font = ImageFont.truetype(f'tools/fonts/{config.FONT_NAME}', fontsize)
indent = fontsize // 6
w, h = font.getsize(text)
text_position = (img.size[0] - w - indent, img.size[1] - h - indent)
draw = ImageDraw.Draw(wm, 'RGBA')
draw.text(text_position, text, font=font, fill=color)
alpha = wm.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(config.TRANSPARENCY)
wm.putalpha(alpha)
out_path = 'images/out/{}/{}'.format(color, new_fname)
Image.composite(wm, img, wm).save(out_path, 'JPEG', optimize=False, quality=config.QUALITY)
def md5(path):
with open(path, 'rb') as f:
md5hash = hashlib.md5()
for chunk in iter(lambda: f.read(4096), b''):
md5hash.update(chunk)
return md5hash.hexdigest()
CODE TWO
# -*- coding: utf-8 -*-
import telebot
import config
import random
import os
import time
from tools.tools import getting_ready
bot = telebot.TeleBot(config.BOT_TOKEN)
#bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.send_message(message.chat.id, 'Hi, Send or Forward me a PHOTO!')
#bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, 'Send /start or /help')
#bot.message_handler(content_types=["photo"])
def send_watermark(message):
chat_id = message.chat.id
sent_message = bot.reply_to(message, 'Downloading...')
message_id = sent_message.message_id
file = bot.get_file(message.photo[0].file_id)
downloaded_file = bot.download_file(file.file_path)
bot.edit_message_text(f'Downloaded!\n\nNow, Genarating Watermarks...\n\ncurrent watermark: {config.WATERMARK}', chat_id=chat_id, message_id=message_id)
__path = 'images/' + str(random.randint(100000, 999999)) + '.tmp'
with open(__path, 'wb') as f:
f.write(downloaded_file)
fname = getting_ready(__path)
os.remove(__path)
time.sleep(2)
bot.edit_message_text('Now, Uploading...', chat_id=chat_id, message_id=message_id)
for i in ('black', 'white'):
__file = 'images/out/{}/{}'.format(i, fname)
__photo = open(__file, 'rb')
bot.send_photo(message.chat.id, __photo, reply_to_message_id=message.message_id)
os.remove(__file)
bot.delete_message(chat_id=chat_id, message_id=message_id)
print('watermark bot started successfully!')
bot.polling()
Steps I've tried
Modified ['black', 'white'] to ['white'] results in an error
Modified for i in ('black', 'white'): to for i in ('white') and results in an error.
I can't figure out what else, tried changing some things I just don't understand like Image.composite(wm, img, wm).save to remove an instance of wm.
I am creating a small level designer in Python (using PyGame).
The program is supposed to just let you place down an image, change between images, export to a PNG file, and export image path and coordinates to where it was place in a text document. I have gotten all of these components to work, but I am stuck with one last component, and that is reading the text document back into PyGame, and re-placing all of the images in the correct places with the correct sprites.
The way that I have it currently (Which has been rewritten and Almost works) produces an error whenever I try to read from one of my exported files.
The error of course is:
stamped_surface.blit(image, (xcrds, ycrds))
TypeError: invalid destination position for blit
Here is my code:
import pygame as pg
import threading
import time
import pygame
from random import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfile
image_file = "../res/ExampleProject/TankGame/TankGameImg/tileGrass_transitionE.png"
f = open("../Saves/Backups/FailSafe.txt", "a+")
f.write("""
#################################################
# PyEngine #
# FailSafe #
# File #
# By MouseBatteries #
#################################################
""")
pg.init()
xcrds = 17
ycrds = 13
black = (0,0,0)
sw = 1280
sh = 720
screen = pg.display.set_mode((sw, sh))
pg.display.set_caption('thing')
image = pg.image.load(image_file).convert()
start_rect = image.get_rect()
image_rect = start_rect
running = True
stamped_surface = pg.Surface((sw, sh))
while running:
event = pg.event.poll()
keyinput = pg.key.get_pressed()
# Escape Program
if keyinput[pg.K_ESCAPE]:
fname = "../Saves/Design_complete.png"
pg.image.save(stamped_surface, fname)
print("File saved at {} ".format(fname))
quit()
#Save Work In Project File
if keyinput[pg.K_s]:
fname = "../Saves/LevelSave.png"
pg.image.save(stamped_surface, fname)
print("File saved at {} ".format(fname))
#Open New Selectable
if keyinput[pg.K_n]:
image_file = askopenfilename()
image = pg.image.load(image_file).convert()
print("Placable Updated!")
if keyinput[pg.K_e]:
fname = "../Saves/Export.png"
pg.image.save(stamped_surface, fname)
print("File saved at {} ".format(fname))
pg.quit()
#Recreate Terrain From File
if keyinput[pg.K_o]:
fileDest = askopenfilename()
openFile = open(fileDest, "r")
for line in openFile:
li = line.strip()
if li.startswith("Pec:"): #pec stands for "PyEngineCoords"
reimgpath = (line.rstrip())
nopecimgpath = reimgpath.replace("Pec:", "")
print(nopecimgpath)
image = pg.image.load(nopecimgpath).convert()
pg.display.update()
if li.startswith("Crdsx:"):
xposcrds = (line.rstrip())
xcrds = xposcrds.replace("Crdsx:", "")
x = int(xcrds)
print(x)
pg.display.update()
if li.startswith("Crdsy:"):
yposcrds = (line.rstrip())
ycrds = yposcrds.replace("Crdsy:", "")
y = int(ycrds)
print(y)
pg.display.update()
stamped_surface.blit(image, (xcrds, ycrds))
elif event.type == pg.QUIT:
running = False
elif event.type == pg.MOUSEMOTION:
image_rect = start_rect.move(event.pos)
elif event.type == pg.MOUSEBUTTONDOWN:
stamped_surface.blit(image, event.pos)
print("Image Placed!")
print(image_file, event.pos)
f.write("\nPec:" + image_file + "\nCrdsx:")
print(event.pos)
xpos_str = str(pg.mouse.get_pos()[0])
ypos_str = str(pg.mouse.get_pos()[1])
f.write(xpos_str)
f.write("\nCrdsy:")
f.write(ypos_str)
f.flush()
screen.fill(black)
screen.blit(stamped_surface, (0, 0))
screen.blit(image, image_rect)
pg.display.flip()
This program has a file system and certain controls to make things happen, so here they are:
ESC KEY - Auto Exports Program For Reference And Quits Program
S Key - Saves Surface as PNG file.
N Key - Prompts User to select new sprite to use
E Key - Exports Image To PNG with file prompt
O Key - Opens File With Coordinate data and image path data.
Image Of Root File System:
https://i.imgur.com/KouhmjK.png
A Few things you should know:
This program auto-saves every file position to the file that contains Coords and Image Paths.
The file system is relatively simple to work out by looking at the code, but if you need some assistance, please ask.
blits((source, dest, area), ...)) -> (Rect, ...) you are missing out the destination. Read here
And if you are making use of coordinates then use square brackets [x-co,y-co]
like this:
block.blit(image,[0,0])
I'm building a gui front-end for a project I've been working on, and I'm having trouble figuring out this specific aspect of PyQT. Long ago there was a post that I had that I think would've solved the problem but I can't quite find it.
Regardless, I have the following files, main.py and playlistcreator.py respectively:
(main.py)
import getpass
import playlistcreator
import os
import sys
import sip
sip.setapi('QString', 2)
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# Window class
class Window(QWidget):
def __init__(self): # constructor for Window (passes "self" -aka Window- to __init__ to initialize it)
super(Window, self).__init__() # inherits from QMainWindow
self.setGeometry(50, 50, 300, 150) # Set window dimensions
self.setWindowTitle("Google Music Playlist Transfer") # Set window title
self.setWindowIcon(QIcon('gmusic.png')) # Set window icon
self.login = QWidget() # login widget ("front page")
self.processing = QWidget() # on successful login - being processing data
self.file_inputs = QWidget() # after processing, ask user where they would like to store data
# call functions
self.loginUI()
self.processingUI()
self.file_inputsUI()
# create stacked widget and add layouts to stack
self.Stack = QStackedWidget(self)
self.Stack.addWidget(self.login)
self.Stack.addWidget(self.processing)
self.Stack.addWidget(self.file_inputs)
main_box = QHBoxLayout(self)
main_box.addWidget(self.Stack)
self.setLayout(main_box)
self.show()
def loginUI(self):
# Set email field
self.email = QLineEdit()
self.email.setMaxLength(110)
self.email.setAlignment(Qt.AlignLeft)
# Set password field
self.pwd = QLineEdit()
self.pwd.setAlignment(Qt.AlignLeft)
self.pwd.setEchoMode(QLineEdit.Password)
# Form layout
form_layout = QFormLayout()
form_layout.addRow("Email: ", self.email)
form_layout.addRow("Password: ", self.pwd)
# Login button
self.login_btn = QPushButton("Login", self) # login button
self.login_btn.clicked.connect(self.process_login) # tell button what to do
self.login_btn.resize(self.login_btn.sizeHint())
# Quit button
self.quit_btn = QPushButton("Exit", self) # exit button
self.quit_btn.clicked.connect(self.close_application) # tell button what to do
# Error label layout
self.error_layout = QHBoxLayout()
# Button box layout
button_box = QHBoxLayout()
button_box.addStretch(1)
button_box.addWidget(self.login_btn)
button_box.addWidget(self.quit_btn)
# input layout (main layout for "home")
input_box = QVBoxLayout()
input_box.addLayout(self.error_layout)
input_box.addLayout(form_layout)
input_box.addLayout(button_box)
self.login.setLayout(input_box)
def processingUI(self):
# setup layout
layout = QHBoxLayout()
# alert user that we're grabbing track data
self.progress_label = QLabel("Grabbing tracks from Google Music. . .")
self.progress_label.setStyleSheet("color: rgb(0, 100, 0);")
layout.addWidget(self.progress_label)
# Get users list of "thumbs up" tracks from Google Music
# set layout
favorite_tracks = self.get_tracks
self.processing.setLayout(layout)
def file_inputsUI(self):
layout = QFormLayout()
# Set text field for directory
self.dir_textbox = QTextEdit(self)
# Add textbox to layout
layout.addRow("Music Directory: ", self.dir_textbox)
self.file_inputs.setLayout(layout)
def close_application(self):
confirm = QMessageBox.question(self, 'Exit Confirmation',
"Are you sure you want to exit?",
QMessageBox.Yes | QMessageBox.No)
if confirm == QMessageBox.Yes:
sys.exit()
else:
pass
def process_login(self):
email_input = str(self.email.text())
pwd_input = str(self.pwd.text())
login_successful = playlistcreator.login(email_input, pwd_input)
if login_successful:
self.Stack.setCurrentIndex(1)
else:
self.error_label = QLabel("Please check your email/password!")
self.error_label.setStyleSheet("color: rgb(255, 0, 0);")
self.error_layout.addWidget(self.error_label)
def get_tracks(self):
tracks = playlistcreator.get_favorite_tracks()
print("You have ", len(tracks), " favorite tracks!")
return tracks
# def open_dir_dialog(self):
# directory = QFileDialog.getExistingDirectory(self, 'Select USB Drive Location')
# self.myTextBox.setText(fileName)
def main():
# Create an PyQT5 application object.
app = QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
# # Input Music Directory
# music_dir = input("Please put the path to your music folder: ")
# list_of_paths = playlistcreator.findmp3(music_dir, favorite_tracks)
# # Input playlist file save location
# playlist_path = input("Where would you like to save the playlist?: ")
# playlist_name = input("What would you like to name the playlist? ")
# playlist_name += ".m3u8"
# # Testing appending file extension to string
# playlistcreator.addtoplaylist(list_of_paths, playlist_path, playlist_name)
# playlistcreator.logout()
main()
(playlistcreator.py)
import os
from gmusicapi import Mobileclient
from mutagen.easyid3 import EasyID3
api = Mobileclient()
songCount = 0
favorite_files_path = []
logged_in = False
def login(email, password):
library = []
if "#" not in email:
email += "#gmail.com"
logged_in = api.login(email, password, Mobileclient.FROM_MAC_ADDRESS)
return logged_in
def get_favorite_tracks():
print("Getting songs from Google Music. . .")
library = api.get_all_songs()
print("There are", len(library), "items in your music library")
good_songs = [song for song in library if song['rating'] == '5']
print("You have", len(good_songs), "favorite tracks!")
return good_songs
def logout():
api.logout()
def findmp3(rootFolder, favoriteTracks):
print("Searching for favorite tracks. . .")
for directory, subdirectory, files in os.walk(rootFolder, topdown=False): # for all files in directory
global songCount
global favorite_files_path
for mp3 in files: # for files in
if mp3.endswith(".mp3"): # if file ends with .mp3
file_path = os.path.join(directory, mp3) # concatenate to create full path
try:
file_tags = EasyID3(file_path) # grab file tags from mp3 file
except:
file_tags = EasyID3() # create tags if none are found
file_tags.save(file_path) # save file to have new tags
if "title" in file_tags:
fileTitle = file_tags["title"][0] # TIT2 = corresponding tag in mutagen for song title
else:
fileTitle = "None"
if "artist" in file_tags:
fileArtist = file_tags["artist"][0] # TPE = corresponding tag in mutagen for artist
else:
fileArtist = "None"
if "album" in file_tags:
fileAlbum = file_tags["album"][0] # TALB = corresponding tag in mutagen for album
else:
fileAlbum = "None"
for track in favoriteTracks:
gMusicTitle = track["title"]
gMusicArtist = track["artist"]
gMusicAlbum = track["album"]
if fileTitle in gMusicTitle and fileArtist in gMusicArtist and fileAlbum in gMusicAlbum: # if file tags (artist, album, title) match gMusic tags
songCount += 1
if songCount == 1:
print("Found 1 song")
else:
print("Found", songCount, "songs") # print updated count of found tracks
favorite_files_path.append(file_path) # add all found files to a list (via their paths)
break # break out of "for track in favorite tracks"
return favorite_files_path
def addtoplaylist(paths, playlist_path, playlist_name):
# Open file (or create if it does not exist)
# change to given directory
try:
os.chdir(playlist_path)
except Exception as err:
print(err)
# open file - if it does not exist, create it
with open(playlist_name, 'a+', encoding="UTF-8") as playlistFile:
print("Adding tracks...", end="")
for track in paths:
print(".", end="")
playlistFile.write(track + '\n')
playlistFile.close()
The problem I've been running into is when the user logs in they hit the processingUI window (which states that the program is grabbing all their tracks from Google) but it doesn't actually seem to be running the get_tracks() method (which is what actually gets the user's tracks from Google), as the program hangs there and doesn't do anything.
I've tested the program without a GUI using straight command line, and it works flawlessly, but I'm not sure what the issue is with the GUI - do I need to thread the execution to start when the proper "window" is brought to the front?