4
\$\begingroup\$

I made my first program in Python using PySimpleGUI. The project turns a YouTube video into an mp3 file and stores it in folder for Spotify to access. I found this idea somewhere and just wanted to give it a go. However since it's my first program, I felt like I should try and get feedback to try and stray away from possible bad habits, or just a cleaner way to write something.

import os
import PySimpleGUI as sg
from pathlib import Path

import pytube.exceptions
from pytube import YouTube

# Checks for directory path that the mp3 files are stored in exists
def is_valid_path(file_path):
    if file_path and Path(file_path).exists():
        return True
    else:
        sg.popup_error("Please specify file directory")


# Function that takes youtube link and gets the video
def _download_song(url: str, path: str):
    yt = YouTube(url)
    # turning the song into an mp3 file
    song = yt.streams.filter(only_audio=True).first()
    # getting the path to put mp3 in
    set_file_dir = os.path.join(path, "sp_songs")
    # gets the mp3 file and puts it in set folder
    audio_file = song.download(output_path=set_file_dir)

    base, ext = os.path.splitext(audio_file)
    new_file = base + ".mp3"
    os.rename(audio_file, new_file)


def settings_window(settings):
    # This is the menu that shows up when you click settings
    settings_layout = [
        [sg.Text("Settings")],
        [sg.Text("Font"), sg.Combo(["Arial", "Comic Sans MS"], settings["GUI"]["font_family"], key="-FONT-")],
        [sg.Text("Font Size"), sg.Combo([8, 10, 12, 14], settings["GUI"]["font_size"], key="-FSIZE-")],
        [sg.Text("Theme"), sg.Combo(sg.theme_list(), settings["GUI"]["theme"], key="-THEME-")],
        [sg.Button("Save Settings")]
    ]

    # Displays the settings layout
    window = sg.Window("Settings Window", settings_layout, size=(250, 180), modal=True)
    while True:
        event, values = window.read()
        if event == sg.WINDOW_CLOSED:
            break

        # Any settings the usec changed are updated in the config.ini here (After the user presses save settings)
        if event == "Save Settings":
            settings["GUI"]["font_family"] = values["-FONT-"]
            settings["GUI"]["font_size"] = values["-FSIZE-"]
            settings["GUI"]["theme"] = values["-THEME-"]

            sg.popup("Please restart program to view changes")
            break

    window.close()


# This is the menu that shows up when the user clicks "How To Use" button
def how_to_window():
    layout = [
        [sg.Text("- First create a folder anywhere on your pc you'd like to store your downloaded videos\n")],
        [sg.Text("- Inside this folder, create another folder called 'sp_songs', it must be spelled"
                 " exactly like that\n")],
        [sg.Text("- Next Open up Spotify on your pc and navigate to your account, and then settings\n")],
        [sg.Text("- Scroll down until you find 'local files' and make sure it's turned on\n")],
        [sg.Text("-Next, click 'Add Source' and navigate to your new folder, and inside that folder"
                 " select sp_songs\n")],
        [sg.Text("- Once you have done this, inside this program select your folder (Do not select the")],
        [sg.Text(" 'sp_songs' folder, click 'update path', and you are ready to start using the program!\n")],
        [sg.Text("- To convert a song, just input a url from YouTube, click convert, and watch as it")],
        [sg.Text("shows up on your spotify!\n")],
        [sg.Text("- Understand that in order to add this song to your playlist, in spotify you must")],
        [sg.Text(" navigate to 'Your Library' and find 'local files'. Your song will show up there.")],
        [sg.Text(" Hover over the song, click the 3 dots to the right of it and add it to your playlist"
                 " as you would any other song.\n")],
        [sg.Text("Thank you for using my program :)")],
        [sg.Button("Exit")]
    ]
    
    # Creates Window
    window = sg.Window("How To Use Program", layout, modal=True)
    
    # Displays window
    while True:
        event, values = window.read()
        if event in (sg.WINDOW_CLOSED, "Exit"):
            break
    window.close()


def main_window():
    # This is the menu that shows up when the user opens the program
    layout = [
        [sg.Text("Convert YouTube to Spotify  "), sg.Input(key="-IN-"), sg.Submit("Convert")],
        [sg.Text("Change Song Path Directory"), sg.Input(settings["DIRECTORY"]["path"], key="-IN2-"),
         sg.FolderBrowse()],
        [sg.Exit(), sg.Button("Settings"), sg.Button("Update Path"), sg.Button("How To Use")]
    ]

    # sets title of window
    window_title = settings["GUI"]["title"]
    # creates window
    window = sg.Window(window_title, layout)

    # displays window
    while True:
        event, values = window.read()

        if event in (sg.WINDOW_CLOSED, "Exit"):
            break
        elif event == "Convert":
            if is_valid_path(values["-IN2-"]):
                try:
                    _download_song(values["-IN-"], values["-IN2-"])
                    sg.popup("Conversion complete! Restart Spotify to add song to playlist :)")
                except pytube.exceptions.RegexMatchError:
                    sg.popup_error("Invalid YouTube Link")
        elif event == "Settings":
            settings_window(settings)
        elif event == "Update Path":
            settings["DIRECTORY"]["path"] = values["-IN2-"]
        elif event == "How To Use":
            how_to_window()

    window.close()


if __name__ == "__main__":
    # Setting up config file and opening main window
    SETTINGS_PATH = str(Path.cwd())
    settings = sg.UserSettings(
        path=SETTINGS_PATH, filename="config.ini", use_config_file=True, convert_bools_and_none=True
    )
    theme = settings["GUI"]["theme"]
    font_size = int(settings["GUI"]["font_size"])
    font_family = settings["GUI"]["font_family"]
    path = settings["DIRECTORY"]["path"]
    sg.theme(theme)
    sg.set_options(font=(font_family, font_size))
    main_window()
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Despite values being a terribly ambiguous name, the following code is very clear:

settings["GUI"]["font_family"] = values["-FONT-"]
settings["GUI"]["font_size"] = values["-FSIZE-"]
settings["GUI"]["theme"] = values["-THEME-"]

That's quite well-done. However, parts like values["-IN-"], values["-IN2-"] are much less clear. In what? And why do we have 2 of those? Significant portions of your code are explaining themselves, not necessarily due to the comments, but this part reminds me of magic numbers. Why is the key -IN- or -IN2- here? The only thing that tells me, is that something isn't going OUT. It could be an input stream, an input file, a path, a link, anything. If you really have to use those names, an explanation would help.

While we're at confusing parts of the code, take a look at the following comment:

# turning the song into an mp3 file
song = yt.streams.filter(only_audio=True).first()

That's not strictly true. You're not turning the song into anything yet, you're simply loading a YouTube stream into a variable.

new_file = base + ".mp3"
os.rename(audio_file, new_file)

Aha! This is where the downloaded song is transformed from an ordinary download into an mp3. The comment could've been accurate here, but it's in the wrong place. Up to this part it seems the code has no idea about mp3 yet, but it's mentioned at least thrice before just in that function. An incorrect comment can do more damage than a missing comment, keep that in mind while writing them. More on comments later.

Honestly, I see nothing in your code setting an encoding. Is it implicit with the library? Otherwise there's nothing guaranteeing you the audio is mp3. It may be wav instead. Or even mp4, a video format! Who knows. You're not specifying and the library isn't telling either.

Moving on to the "How to use":

layout = [
    [sg.Text("- First create a folder anywhere on your pc you'd like to store your downloaded videos\n")],
    [sg.Text("- Inside this folder, create another folder called 'sp_songs', it must be spelled"
             " exactly like that\n")],
    [sg.Text("- Next Open up Spotify on your pc and navigate to your account, and then settings\n")],
    [sg.Text("- Scroll down until you find 'local files' and make sure it's turned on\n")],
    [sg.Text("-Next, click 'Add Source' and navigate to your new folder, and inside that folder"
             " select sp_songs\n")],
    [sg.Text("- Once you have done this, inside this program select your folder (Do not select the")],
    [sg.Text(" 'sp_songs' folder, click 'update path', and you are ready to start using the program!\n")],
    [sg.Text("- To convert a song, just input a url from YouTube, click convert, and watch as it")],
    [sg.Text("shows up on your spotify!\n")],
    [sg.Text("- Understand that in order to add this song to your playlist, in spotify you must")],
    [sg.Text(" navigate to 'Your Library' and find 'local files'. Your song will show up there.")],
    [sg.Text(" Hover over the song, click the 3 dots to the right of it and add it to your playlist"
             " as you would any other song.\n")],
    [sg.Text("Thank you for using my program :)")],
    [sg.Button("Exit")]
]

First of all, it's great to include such a window. Getting stuck in a program and not having a clue where to get the documentation from is frustrating. You clearly took an effort to remedy that. However, you had to write out sg.Text 13x to do that.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.