Let's automatically display the lyrics of the song being played on iTunes in Python (improved version)

Introduction

We have added a lot of functions to the previously created "Automatically display the lyrics of the song being played on iTunes in Python".

Improvement points

--Supports song skipping --Speed up display --App control --Automatic scrolling --Improved lyrics search accuracy

Supports skipping songs

Once the lyrics page of a song was opened, the page was displayed until the end of that song, but if you skip to the next song, the lyrics will also display the next song.

Change before


while True:
    start = time.time()  # delete

    # ~~~~~~~~

    time.sleep(music_time - (time.time() - start))  # delete

After change


prev_track_name = ""  # add
while True:
    #Song name, album name, artist name, song length being played
    name = music.current_track.name.get()
    artist = music.current_track.artist.get()
    album = music.current_track.album.get()
    music_time = music.current_track.time.get()  # m:s str

    # add-start
    if name == prev_track_name:
        time.sleep(1)
        continue

    prev_track_name = name
    # add-end

    # ~~~~~~~~

    time.sleep(1)  # add

Faster display

I set a timeout because it took a long time to display the lyrics page.

After change


driver = webdriver.Chrome(executable_path="chromedriver")
driver.get("https://www.google.com/")  #Initial tab
driver.set_page_load_timeout(5)  #Maximum read wait time (5 seconds in this case)# add

The lyrics themselves can be read in 5 seconds, but other images will take a long time to load the page, so it will be forcibly terminated after 5 seconds. By the way, "Scroll to the position of the lyrics" was also changed to find the position of the lyrics and scroll to that position.

Change before


while True:
    # ~~~~~~~~

    try:
        # ~~~~~~~~

        #Open in new tab
        driver.execute_script("window.open()")
        driver.switch_to.window(driver.window_handles[1])
        driver.get("https://www.uta-net.com/" + name_url)
        driver.execute_script("window.scrollTo(0, 380);")  #Scroll to the position of the lyrics
        #Close previous tab
        driver.switch_to.window(driver.window_handles[0])
        driver.close()
        driver.switch_to.window(driver.window_handles[0])

After change


while True:
    # ~~~~~~~~

    try:
        # ~~~~~~~~

        #Open in new tab
        driver.execute_script("window.open()")
        driver.switch_to.window(driver.window_handles[1])

        # add-start
        try:
            driver.get("https://www.uta-net.com/" + name_url)
        except:
            pass
        #Scroll to the position of the lyrics
        driver.execute_script("arguments[0].scrollIntoView();", driver.find_element_by_id("view_kashi"))
        # add-end

        #Close previous tab
        driver.switch_to.window(driver.window_handles[0])
        driver.close()
        driver.switch_to.window(driver.window_handles[0])

App control

It's almost a bonus, but I made it possible to control "playback" and "to the next song" even on the terminal. First is the basic operation.

basic operation


music = appscript.app("Music")

#Regeneration
music.play()

#pause
music.pause()

#Play / Pause
music.playpause()

#To the previous track
music.previous_track()

#To the next track
music.next_track()

Use this as it is. Also, with normal ʻinput ()`, it is not possible to wait until input is made and perform other processing, so I used input with a timeout.

Input with timeout


from select import select
import sys

#The arguments are "read", "write", "exception", and "waiting time" in order, and this time only read is used.
#Wait time is 0.Specified as 5 seconds
# 0.If there is no input after 5 seconds, an empty list is returned
read, _, _ = select([sys.stdin], [], [], 0.5)

if read:
    command = sys.stdin.readline().strip()
else:
    command = ""

I will put the above in the code as it is.

After change


while True:
    #Access the Music app
    music = appscript.app("Music")

    # add-start
    # ----App control----

    #Input with timeout
    read, _, _ = select([sys.stdin], [], [], 0.5)

    if read:
        command = sys.stdin.readline().strip()
    else:
        command = ""

    if command == "b":  #To the previous track
        music.previous_track()
    elif command == "p":  #Play / Pause
        music.playpause()
    elif command == "n":  #To the next track
        music.next_track()
    # add-end

    # ~~~~~~~~

Auto scroll

Since the entire lyrics may not be displayed, the lyrics are automatically scrolled.

After change


while True:
    # ~~~~~~~~

    if name == prev_track_name:
        time.sleep(1)

        # add-start
        count += 1
        if count % 5 == 0:
            driver.execute_script(
                "window.scrollTo(window.pageXOffset, window.pageYOffset + " + str(kashi_length // music_time * 5) + ");"
            )
        # add-end

        continue

        # ~~~~~~~~

        #Open in new tab
        driver.execute_script("window.open()")
        driver.switch_to.window(driver.window_handles[1])
        try:
            driver.get("https://www.uta-net.com/" + name_url)
        except:
            pass
        #Scroll to the position of the lyrics
        driver.execute_script("arguments[0].scrollIntoView();", driver.find_element_by_id("view_kashi"))

        # add-start
        #The length of the lyrics part on the page
        kashi_length = driver.find_element_by_id("view_mylink").location["y"] - \
                       driver.find_element_by_id("view_kashi").location["y"]
        # add-end

        #Close previous tab
        driver.switch_to.window(driver.window_handles[0])
        driver.close()
        driver.switch_to.window(driver.window_handles[0])

Get the length of the lyrics part in the page (lyric length / song length) * 5 Scroll down every 5 seconds to scroll at a reasonable pace.

Improved lyrics search accuracy

First, convert the full-width alphabet to half-width. Also, when searching, "exact match" was changed to "contains".

After change


while True:
    # ~~~~~~~~

    # ----Access the lyrics site----

    #Full-width to half-width# add
    name = str(name).translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))

    name = parse.quote(name)  #Percent encoding
    url = "https://www.uta-net.com/search/?Aselect=2&Keyword=" + name + "&Bselect=3&x=0&y=0"  # Bselect=4 to Bselect=To 3

In addition, the position of the singer's name may shift due to the influence of the crown mark on the page with a lot of access, so this has been fixed.

After change


while True:
    # ~~~~~~~~

    try:
        # ~~~~~~~~

        name_url = ""
        flag = False
        for tag_tr in tr:
            a = tag_tr.find_all("a")
            for i, tag_a in enumerate(a):
                if i == 0:  #Song title
                    name_url = tag_a.get("href")
                elif i == 1 or i == 2:  #Singer name#Add 2 where there was only 1
                    if tag_a.string == artist:
                        flag = True
                        break
            if flag:
                break

Whole code

import time
import sys
from select import select

import appscript
from urllib import request, parse
from bs4 import BeautifulSoup
from selenium import webdriver

driver = webdriver.Chrome(executable_path="chromedriver")
driver.get("https://www.google.com/")  #Initial tab
driver.set_page_load_timeout(5)  #It can be shorter depending on the speed of the line

music_time = 0
prev_track_name = ""
count = 0
kashi_length = 0
while True:
    #Access the Music app
    music = appscript.app("Music")

    # ----App control----

    #Input with timeout
    read, _, _ = select([sys.stdin], [], [], 0.5)

    if read:
        command = sys.stdin.readline().strip()
    else:
        command = ""

    if command == "b":  #To the previous track
        music.previous_track()
    elif command == "p":  #Play / Pause
        music.playpause()
    elif command == "n":  #To the next track
        music.next_track()

    # ----Get song title----

    #Song name, album name, artist name, song length being played
    name = music.current_track.name.get()
    artist = music.current_track.artist.get()
    album = music.current_track.album.get()
    music_time = music.current_track.time.get()  # m:s str

    # music_time to seconds
    music_time = music_time.split(":")
    music_time = int(music_time[0]) * 60 + int(music_time[1])

    if name == prev_track_name:
        time.sleep(1)
        count += 1
        if count % 5 == 0:
            driver.execute_script(
                "window.scrollTo(window.pageXOffset, window.pageYOffset + " + str(kashi_length // music_time * 5) + ");"
            )
        continue

    prev_track_name = name

    print("{} / {} / {}".format(name, artist, album))

    # ----Access the lyrics site----

    #Full-width to half-width
    name = str(name).translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))

    name = parse.quote(name)  #Percent encoding
    url = "https://www.uta-net.com/search/?Aselect=2&Keyword=" + name + "&Bselect=3&x=0&y=0"

    try:
        html = request.urlopen(url)
        soup = BeautifulSoup(html, "html.parser")

        tr = soup.find_all("tr")

        name_url = ""
        flag = False
        for tag_tr in tr:
            a = tag_tr.find_all("a")
            for i, tag_a in enumerate(a):
                if i == 0:  #Song title
                    name_url = tag_a.get("href")
                elif i == 1 or i == 2:  #Singer name
                    if tag_a.string == artist:
                        flag = True
                        break
            if flag:
                break

        #Open in new tab
        driver.execute_script("window.open()")
        driver.switch_to.window(driver.window_handles[1])
        try:
            driver.get("https://www.uta-net.com/" + name_url)
        except:
            pass
        #Scroll to the position of the lyrics
        driver.execute_script("arguments[0].scrollIntoView();", driver.find_element_by_id("view_kashi"))
        kashi_length = driver.find_element_by_id("view_mylink").location["y"] - \
                       driver.find_element_by_id("view_kashi").location["y"]
        #Close previous tab
        driver.switch_to.window(driver.window_handles[0])
        driver.close()
        driver.switch_to.window(driver.window_handles[0])

    except:
        pass

    print("b:Before| p:Play / Pause| n:Next")
    print()

    time.sleep(1)

Recommended Posts

Let's automatically display the lyrics of the song being played on iTunes in Python (improved version)
Let's automatically display the lyrics of the song being played on iTunes in Python
Let's use the Python version of the Confluence API module.
Not being aware of the contents of the data in python
Let's use the open data of "Mamebus" in Python
Put the latest version of Python on linux (Debian) on Chromebook
How is the progress? Let's get on with the boom ?? in Python
Let's measure the test coverage of pushed python code on GitHub.
[Cloudian # 9] Try to display the metadata of the object in Python (boto3)
[Python] Let's reduce the number of elements in the result in set operations
How to update the python version of Cloud Shell on GCP
Get the number of readers of a treatise on Mendeley in Python
pyenv-change the python version of virtualenv
Waveform display of audio in Python
Change the Python version of Homebrew
Let's change the color scheme of iTerm2 automatically depending on the time zone
[Android] Display images on the web in the info Window of Google Map
Display the status of COVID 19 infection in Japan with Splunk (GitHub version)
I tried to get the RSS of the top song of the iTunes store automatically
Check the behavior of destructor in Python
Django ~ Let's display it in the browser ~
Display a list of alphabets in Python 3
About the virtual environment of python version 3.7
Display Python 3 in the browser with MAMP
The result of installing python in Anaconda
Let's claim the possibility of pyenv-virtualenv in 2021
[Python] Try pydash of the Python version of lodash
Prevent double launch in Python (improved version)
Display the graph of tensorBoard on jupyter
The basics of running NoxPlayer in Python
In search of the fastest FizzBuzz in Python
I want to use Python in the environment of pyenv + pipenv on Windows 10
I installed Pygame with Python 3.5.1 in the environment of pyenv on OS X
I compared the speed of regular expressions in Ruby, Python, and Perl (2013 version)
Let's play with Python Receive and save / display the text of the input form
In Python, change the behavior of the method depending on how it is called
Set an upper limit on the number of recursive function iterations in Python
Visualize the timeline of the number of issues on GitHub assigned to you in Python
Output the number of CPU cores in Python
Try the python version of emacs-org parser orgparse
[Python] Sort the list of pathlib.Path in natural sort
Let's parse the git commit log in Python!
Get the caller of a function in Python
Match the distribution of each group in Python
View the result of geometry processing in Python
Make a copy of the list in Python
Use the latest version of PyCharm on Ubuntu
A note about the python version of python virtualenv
Find the divisor of the value entered in python
[Python] Display the Altair legend in the plot area
Try the free version of Progate [Python I]
Find the solution of the nth-order equation in python
The story of reading HSPICE data in Python
[Note] About the role of underscore "_" in Python
About the behavior of Model.get_or_create () of peewee in Python
Solving the equation of motion in Python (odeint)
Output in the form of a python array
At the time of python update on ubuntu
I want to display the progress in Python!
[Example of Python improvement] I learned the basics of Python on a free site in 2 weeks.
[Machine learning] "Abnormality detection and change detection" Let's draw the figure of Chapter 1 in Python.