pythonpython-3.xspotifyapi-designvk

Continuously real-time fetching currently playing song on Spotify


I wrote the script that puts Spotify user's currently playing song to the status on vk.com. It's like a one-time thing now. When you run the script - it sets the correct status. But to update it, you obviously will need to run the script again.

I wonder if there is a possibility to make it work dynamically? Update the status, when the new song starts. I can think only of a setting a schedule to run the script or sending requests to check if the song has changed. But I imagine it will work only if a user's PC is always on and hence the script is ready to run.

The other problem is that the spotify token lasts one hour, but I read that the refresh token is practically valid forever, or until it has been manually revoked. Vk token has an official option to make token valid forever.

import config
import webbrowser
import requests
import furl
import secrets
import string
import time
import os
import simplejson as json


URL_CODE_BASE_VK = 'https://oauth.vk.com/authorize'
URL_CODE_BASE_SP = 'https://accounts.spotify.com/authorize'
URL_TOKEN_VK = 'https://oauth.vk.com/access_token'
URL_TOKEN_SP = 'https://accounts.spotify.com/api/token'
URL_TRACK = 'https://api.spotify.com/v1/me/player/currently-playing'
URL_STATUS = 'https://api.vk.com/method/status.set'
EXP_IN_TOKEN_SP = 3400
EXP_IN_TOKEN_VK = 86400
FILE_TOKEN_VK = 'vk_token.json'
FILE_TOKEN_SP = 'sp_token.json'


def get_auth_code_vk():
    url_code_params = {
                        'client_id': config.CLIENT_ID_VK,
                        'response_type': 'code',
                        'redirect_uri': 'https://oauth.vk.com/blank.html',
                        'v': 5.92,
                        'scope': 'status',
                        'state': gen_state(),
                        'display': 'page'
    }

    code = url_open(URL_CODE_BASE_VK, url_code_params)
    return parse_code(code)


def get_auth_code_sp():
    url_code_params = {
                        'client_id': config.CLIENT_ID_SP,
                        'response_type': 'code',
                        'redirect_uri': 'https://www.spotify.com/',
                        'scope': 'user-read-currently-playing',
                        'state': gen_state()
    }

    code = url_open(URL_CODE_BASE_SP, url_code_params)
    return parse_code(code)


def gen_state():
    symbols = string.ascii_lowercase + string.digits
    return ''.join(secrets.choice(symbols) for _ in range(12))


def url_open(url_base, url_params):
    url_code_full = furl.furl(url_base).add(url_params).url
    webbrowser.open_new_tab(url_code_full)
    input_url = input('Enter the whole URL, that you have been redirected on: ')

    return input_url


def parse_code(url):
    return (url.split("code=")[1]).split("&state=")[0]


def get_token_vk():
    data = {
            'grant_type': 'authorization_code',
            'code': get_auth_code_vk(),
            'redirect_uri': 'https://oauth.vk.com/blank.html',
            'client_id': 6782333,
            'client_secret': config.CLIENT_SECRET_VK
    }

    response = requests.post(url=URL_TOKEN_VK, data=data).json()
    write_file(FILE_TOKEN_VK, response)


def get_token_sp():
    data = {
            'grant_type': 'authorization_code',
            'code': get_auth_code_sp(),
            'redirect_uri': 'https://www.spotify.com/',
            'client_id': config.CLIENT_ID_SP,
            'client_secret': config.CLIENT_SECRET_SP
    }

    response = requests.post(url=URL_TOKEN_SP, data=data).json()
    write_file(FILE_TOKEN_SP, response)


def write_file(tkn_file, response):
    dict = {}
    dict['token'] = response["access_token"]
    dict['time'] = time.time()

    with open(tkn_file, 'w') as file:
        file.write(json.dumps(dict))


def load_file(tkn_file):
    with open(tkn_file) as file:
        data = json.load(file)
    return data


def set_status():
    params = {
              'v': 5.92,
              'access_token': load_file(FILE_TOKEN_VK)['token'],
              'text': current_track()
    }

    set_status = requests.get(url=URL_STATUS, params=params)


def track_data():
    tkn_file =  load_file(FILE_TOKEN_SP)['token']
    headers = {
               'Accept': 'application/json',
               'Authorization': f'Bearer {tkn_file}'
    }

    return requests.get(url=URL_TRACK, headers=headers)


def current_track():
    data = track_data().json()
    artist = data['item']['artists'][0]['name']
    track = data['item']['name']

    return(f'{artist} - {track}')


def check_playback():
    try:
        set_status()
        print(current_track())
    except json.decoder.JSONDecodeError:
        print('Not playing')


def token_missing(file):
    return not os.path.isfile(file)


def token_expired(file, exp_in):
    return time.time() - load_file(file)['time'] > exp_in


def token_not_valid(file, exp_in):
    return token_missing(file) or token_expired(file, exp_in)


def run_script():
    if token_not_valid(FILE_TOKEN_VK, EXP_IN_TOKEN_VK):
        get_token_vk()

    if token_not_valid(FILE_TOKEN_SP, EXP_IN_TOKEN_SP):
        get_token_sp()

    check_playback()


if __name__ == "__main__":
    run_script()

Solution

  • Yes, you can use a cron job to make a process run at set intervals. Also if you build this into a flask app then you can use a scheduler to run the job at set intervals. Probably cron is the quickest way though. To edit cronjobs:

    $ crontab -e
    

    Then add something like:

    * * * * * python /tmp/spotify_update.py
    

    To run the job every second. The asterisks represent minutes, hours, days, months, and weekdays.