コード例 #1
0
class YoutubeClient:
    """
        The Youtube client class used to interface with the Youtube API.
    """

    def __init__(self):
        self._api_service_name = "youtube"
        self._api_version = "v3"
        # The scopes of permissions request from the user
        self._scopes = ["https://www.googleapis.com/auth/youtube.readonly"]
        # Parameter store to get and update Spotify secrets
        self._parameter_store = ParameterStore('Youtube', constants.YOUTUBE_SECRETS)
        self._credentials = self._init_credentials()
        self._client = self._init_youtube_client()

    def _init_credentials(self):
        """
            Instantiates and returns a Credentials object. This is used to
            instantiate the Youtube API client, and to refresh the Youtube
            access token on expiration.
        """

        youtube_secrets = self._parameter_store.get_secrets()

        return Credentials (
            token=youtube_secrets.get("access_token"),
            refresh_token=youtube_secrets.get("refresh_token"),
            token_uri=youtube_secrets.get("token_uri"),
            client_id=youtube_secrets.get("client_id"),
            client_secret=youtube_secrets.get("client_secret"),
            scopes=self._scopes
        )

    def _init_youtube_client(self):
        """
            Instantiates and returns a Youtube API client.
        """

        return build(
            self._api_service_name,
            self._api_version,
            credentials=self._credentials,
            cache_discovery=False
        )

    def refresh(self):
        """
            Refreshes the Youtube access token.
        """

        self._credentials.refresh(Request())

        self._parameter_store.update_secrets({
            "access_token": self._credentials.token,
            "refresh_token": self._credentials.refresh_token
        })

        self._client = build(
            self._api_service_name,
            self._api_version,
            credentials=self._credentials
        )

    def get_liked_videos(self, pageToken = None):
        """
            Returns the provided page of the user's liked Youtube videos 
        """

        request = self._client.videos().list(
            part="snippet",
            maxResults=10,
            myRating="like",
            pageToken=pageToken,
            fields="items(id,snippet.title),nextPageToken"
        )

        return request.execute()

    def get_valid_songs(self, response, recent_video_id):
        """
            Iterates through the provided liked videos response from the Youtube
            API, and uses YoutubeDL to parse out the videos that are music
            tracks.
        """

        valid_songs = []
        already_processed = False

        ydl_opts = {
            'skip_download': True,
            'quiet': True,
            'no_warnings': True
        }

        for item in response["items"]:            
            if item["id"] == recent_video_id:
                print("[NOTICE] Reached already processed video.")
                already_processed = True
                break

            youtube_url = "https://www.youtube.com/watch?v={}".format(
                item["id"]
            )

            try:
                # Get a Youtube video's info
                video = YoutubeDL(ydl_opts).extract_info(
                    youtube_url,
                    download=False
                )
            except:
                continue

            song_name = video["track"]
            artist = video["artist"]

            if song_name and artist:
                # If the video is a music track, add it to the valid songs array
                valid_songs.append ({
                    "title": song_name,
                    "artist": artist
                })

        return valid_songs, already_processed

    def store_recent_video_id(self, video_id):
        """
            Stores the video id of the most recently liked video.
        """

        self._parameter_store.update_secrets({
            "recent_video_id": video_id
        })

    def get_recent_video_id(self):
        """
            Returns the video id of the most recently liked video.
        """

        youtube_secrets = self._parameter_store.get_secrets()
        return youtube_secrets.get("recent_video_id")
コード例 #2
0
class SpotifyClient:
    """
        The Spotify client class used to interface with the Spotify Web API.
    """
    def __init__(self):
        # The scope of permissions request from the user
        self._scope = "playlist-modify-public"
        # Parameter store to get and update Spotify secrets
        self._parameter_store = ParameterStore('Spotify',
                                               constants.SPOTIFY_SECRETS)
        self._sp_oauth = self._init_spotify_oauth()
        self._client = self._init_spotify_client()

    def _init_spotify_oauth(self):
        """
            Instantiates and returns a SpotifyOAuth object. This is used to
            refresh the Spotify access token on expiration.
        """

        spotify_secrets = self._parameter_store.get_secrets()

        return oauth2.SpotifyOAuth(
            client_id=spotify_secrets.get("client_id"),
            client_secret=spotify_secrets.get("client_secret"),
            redirect_uri=spotify_secrets.get("redirect_uri"),
            scope=self._scope)

    def _init_spotify_client(self):
        """
            Instantiates and returns a Spotify Web API client.
        """

        spotify_secrets = self._parameter_store.get_secrets()
        return spotipy.Spotify(auth=spotify_secrets.get("access_token"))

    def refresh(self):
        """
            Refreshes the Spotify access token.
        """

        spotify_secrets = self._parameter_store.get_secrets()

        token_info = self._sp_oauth.refresh_access_token(
            spotify_secrets.get('refresh_token'))

        self._parameter_store.update_secrets({
            "access_token":
            token_info["access_token"],
            "refresh_token":
            token_info["refresh_token"]
        })

        self._client = spotipy.Spotify(auth=token_info.get("access_token"))

    def get_playlist(self):
        """
            Returns the playlist id of the user's "Youtube Liked Videos"
            playlist on Spotify
        """

        spotify_secrets = self._parameter_store.get_secrets()

        playlist_id = spotify_secrets.get("playlist_id")

        if playlist_id:
            # If a playlist parameter exists, check to see that it exists
            # in the user's spotify and return its id
            try:
                playlist = self._client.playlist(playlist_id)
                return playlist['id']
            except spotipy.exceptions.SpotifyException:
                # If there is an exception (i.e. the playlist does not exist),
                # create it and return its id
                return self._create_playlist()
        else:
            # If the playlist does not exist, create it and return its id
            return self._create_playlist()

    def _create_playlist(self):
        """
            Creates a new Spotify playlist and returns its id
        """

        user_id = self._client.me()['id']

        response = self._client.user_playlist_create(
            user=user_id,
            name="Youtube Liked Songs",
            public=False,
            description="My Youtube liked songs")

        playlist_id = response["id"]

        self._parameter_store.update_secrets({"playlist_id": playlist_id})

        return playlist_id

    def add_songs_to_playlist(self, songs, playlist_id, existing_track_uris):
        """
            Adds the provided tracks to the provided playlist
        """

        if not songs:
            return

        track_uris = []

        for song in songs:
            # Query the Spotify API for the current track
            search_results = self._client.search(
                self._format_query(song["title"], song["artist"]))

            tracks = search_results["tracks"]["items"]

            if not tracks:
                # If the track could not be found on Spotify, continue
                continue

            track_uri = tracks[0]["uri"]

            if track_uri in existing_track_uris:
                # If the track already exists in the playlist, continue
                print("Track already in playlist")
                continue

            track_uris.append(track_uri)

        if not track_uris:
            return

        user_id = self._client.me()['id']

        self._client.user_playlist_add_tracks(user_id, playlist_id, track_uris)

    def _format_query(self, title, artist):
        """
            Formats the track query for the Spotify API
        """

        return "{track} artist:{artist}".format(track=title, artist=artist)

    def get_existing_tracks(self, playlist_id):
        """
            Returns the uris of all the tracks currently in the playlist
        """

        track_uris = []
        user_id = self._client.me()['id']

        playlist = self._client.user_playlist(user_id, playlist_id)

        while playlist:
            # Iterate through all pages of track results from the playlist
            for track in playlist["tracks"]["items"]:
                track_uris.append(track["track"]['uri'])
            if playlist["tracks"]["next"]:
                playlist = self._client.next(playlist["tracks"])
            else:
                playlist = None

        return track_uris