コード例 #1
0
def _get_audius_search_results(query, formats):
    Track = apps.get_model("music", "Track")
    Request = apps.get_model("networking", "Request")

    data = {
        "query": query,
        "app_name": "Jukebox Radio",
    }

    response = make_request(
        Request.TYPE_GET,
        "https://discoveryprovider.audius5.prod-us-west-2.staked.cloud/v1/tracks/search",
        data=data,
    )
    response_json = response.json()
    cleaned_data = []

    for item in response_json["data"]:
        cleaned_data.append(
            {
                "format": Track.FORMAT_TRACK,
                "provider": GLOBAL_PROVIDER_AUDIUS,
                "external_id": item["id"],
                "name": item["title"],
                "artist_name": item["user"]["name"],
                "album_name": "N/A",
                "img_url": (item["artwork"] and item["artwork"]["1000x1000"]) or "N/A",
                "duration_ms": item["duration"] * 1000,
            }
        )

    return cleaned_data
コード例 #2
0
def _get_youtube_search_results(query, formats):
    """
    Get YouTube search results
    """
    Track = apps.get_model("music", "Track")
    Request = apps.get_model("networking", "Request")

    formats = set(formats).intersection(set([Track.FORMAT_VIDEO]))

    if not formats:
        return []

    data = {
        "part": "snippet",
        "q": query,
        "key": settings.GOOGLE_API_KEY,
        "type": ",".join(formats),
        "videoEmbeddable": True,
        "maxResults": 25,
    }

    response = make_request(
        Request.TYPE_GET,
        "https://www.googleapis.com/youtube/v3/search",
        data=data,
        headers={
            "Content-Type": "application/json",
        },
    )
    response_json = response.json()

    cleaned_data = []
    if "items" not in response_json:
        return cleaned_data

    for item in response_json["items"]:

        youtube_id = item["id"]["videoId"]
        youtube_channel_name = item["snippet"]["channelTitle"]
        youtube_video_name = item["snippet"]["title"]
        youtube_img_lg = item["snippet"]["thumbnails"]["high"]["url"]

        cleaned_data.append(
            {
                "format": Track.FORMAT_VIDEO,
                "provider": GLOBAL_PROVIDER_YOUTUBE,
                "external_id": youtube_id,
                "name": youtube_video_name,
                "artist_name": youtube_channel_name,
                "album_name": "",  # TODO maybe this shouldn't just be an empty string
                "img_url": youtube_img_lg,
            }
        )

    return cleaned_data
コード例 #3
0
    def post(self, request, **kwargs):
        """
        Spotify redirects a user to this URL after the Spotify authorization
        process.
        """
        Request = apps.get_model("networking", "Request")

        user = request.user

        code = self.param(request, "code")
        error = self.param(request, "error")

        if error:
            return self.http_response_400(error)

        data = {
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": generate_redirect_uri(request),
            "client_id": settings.SPOTIFY_CLIENT_ID,
            "client_secret": settings.SPOITFY_CLIENT_SECRET,
        }

        response = make_request(
            Request.TYPE_POST,
            "https://accounts.spotify.com/api/token",
            data=data,
            user=user,
        )
        response_json = response.json()

        cipher_suite = Fernet(settings.FERNET_KEY)

        token = response_json["access_token"]
        token_utf8 = token.encode("utf-8")
        encrypted_token_utf8 = cipher_suite.encrypt(token_utf8)
        encrypted_token = encrypted_token_utf8.decode("utf-8")
        user.encrypted_spotify_access_token = encrypted_token

        token = response_json["refresh_token"]
        token_utf8 = token.encode("utf-8")
        encrypted_token_utf8 = cipher_suite.encrypt(token_utf8)
        encrypted_token = encrypted_token_utf8.decode("utf-8")
        user.encrypted_spotify_refresh_token = encrypted_token

        user.spotify_scope = ",".join(settings.SPOTIFY_USER_DATA_SCOPES)
        user.save()

        return self.http_response_200()
コード例 #4
0
def _refresh_track_spotify_data(track, user):
    Request = apps.get_model("networking", "Request")
    response = make_request(
        Request.TYPE_GET,
        f"https://api.spotify.com/v1/tracks/{track.spotify_id}",
        headers={
            "Authorization": f"Bearer {user.spotify_access_token}",
            "Content-Type": "application/json",
        },
    )
    response_json = response.json()

    # TODO refresh more data points
    track.duration_ms = response_json["duration_ms"]
    track.save()
コード例 #5
0
def _refresh_track_youtube_data(track):
    Request = apps.get_model("networking", "Request")

    data = {
        "part": "snippet,contentDetails",
        "id": track.youtube_id,
        "key": settings.GOOGLE_API_KEY,
    }

    response = make_request(
        Request.TYPE_GET,
        "https://www.googleapis.com/youtube/v3/videos",
        data=data,
        headers={"Content-Type": "application/json"},
    )

    response_json = response.json()

    # clean duration
    duration_raw = response_json["items"][0]["contentDetails"]["duration"]

    duration_ms = 0
    mode = None
    val = ""
    for char in duration_raw:
        if char in ["P", "T"]:
            continue

        if char in ["H", "M", "S"]:
            if char == "H":
                duration_ms += int(val) * 60 * 60 * 1000
            elif char == "M":
                duration_ms += int(val) * 60 * 1000
            elif char == "S":
                duration_ms += int(val) * 1000
            else:
                raise ValueError(f"Unexpected playtime character: {mode}")

            val = ""
            continue

        val += char

    # TODO refresh more data points
    track.duration_ms = duration_ms
    track.save()
コード例 #6
0
ファイル: tasks.py プロジェクト: 0x213F/jukebox-radio-django
def refresh_spotify_access_tokens():
    Request = apps.get_model("networking", "Request")

    cipher_suite = Fernet(settings.FERNET_KEY)
    user_qs = User.objects.filter(encrypted_spotify_refresh_token__isnull=False)

    for user in user_qs:

        try:
            encrypted_token = user.encrypted_spotify_refresh_token
            encrypted_token_utf8 = encrypted_token.encode("utf-8")
            token_utf8 = cipher_suite.decrypt(encrypted_token_utf8)
            token = token_utf8.decode("utf-8")

            data = {
                "grant_type": "refresh_token",
                "refresh_token": token,
                "client_id": settings.SPOTIFY_CLIENT_ID,
                "client_secret": settings.SPOITFY_CLIENT_SECRET,
            }

            response = make_request(
                Request.TYPE_POST,
                "https://accounts.spotify.com/api/token",
                data=data,
                user=user,
            )
            response_json = response.json()

            token = response_json["access_token"]
            token_utf8 = token.encode("utf-8")
            encrypted_token_utf8 = cipher_suite.encrypt(token_utf8)
            encrypted_token = encrypted_token_utf8.decode("utf-8")

            user.encrypted_spotify_access_token = encrypted_token
            user.save()

        except Exception:
            user.encrypted_spotify_access_token = None
            user.encrypted_spotify_refresh_token = None
            user.spotify_scope = None
            user.save()
コード例 #7
0
def _get_apple_music_search_results(query, formats):
    Collection = apps.get_model("music", "Collection")
    Track = apps.get_model("music", "Track")
    Request = apps.get_model("networking", "Request")

    formats = set(formats).intersection(
        set([Track.FORMAT_TRACK, Collection.FORMAT_ALBUM, Collection.FORMAT_PLAYLIST])
    )
    if Track.FORMAT_TRACK in formats:
        formats.remove(Track.FORMAT_TRACK)
        formats.add("songs")
    if Collection.FORMAT_ALBUM in formats:
        formats.remove(Collection.FORMAT_ALBUM)
        formats.add("albums")
    if Collection.FORMAT_PLAYLIST in formats:
        formats.remove(Collection.FORMAT_PLAYLIST)
        formats.add("playlists")
    formats.add("music-videos")

    data = {
        "term": query,
        "types": ",".join(formats),
    }

    apple_music_token = generate_apple_music_token()

    response = make_request(
        Request.TYPE_GET,
        "https://api.music.apple.com/v1/catalog/us/search",
        data=data,
        headers={
            "Authorization": f"Bearer {apple_music_token}",
        },
    )
    response_json = response.json()
    cleaned_data = []

    if "albums" in response_json["results"].keys():
        items = response_json["results"]["albums"]["data"]
        for item in items:
            cleaned_data.append(
                {
                    "format": Collection.FORMAT_ALBUM,
                    "provider": "apple_music",
                    "external_id": item["id"],
                    "name": item["attributes"]["name"],
                    "artist_name": item["attributes"]["artistName"],
                    "img_url": item["attributes"]["artwork"]["url"],
                }
            )

    if "playlists" in response_json["results"].keys():
        items = response_json["results"]["playlists"]["data"]
        for item in items:
            cleaned_data.append(
                {
                    "format": Collection.FORMAT_PLAYLIST,
                    "provider": "apple_music",
                    "external_id": item["id"],
                    "name": item["attributes"]["name"],
                    "artist_name": item["attributes"]["curatorName"],
                    "img_url": item["attributes"]["artwork"]["url"],
                }
            )

    if "songs" in response_json["results"].keys():
        items = response_json["results"]["songs"]["data"]
        for item in items:
            cleaned_data.append(
                {
                    "format": Track.FORMAT_TRACK,
                    "provider": "apple_music",
                    "external_id": item["id"],
                    "name": item["attributes"]["name"],
                    "artist_name": item["attributes"]["artistName"],
                    "album_name": item["attributes"]["albumName"],
                    "img_url": item["attributes"]["artwork"]["url"],
                    "duration_ms": item["attributes"]["durationInMillis"],
                }
            )

    if "music-videos" in response_json["results"].keys():
        items = response_json["results"]["music-videos"]["data"]
        for item in items:
            print(item)
            cleaned_data.append(
                {
                    "format": Track.FORMAT_VIDEO,
                    "provider": "apple_music",
                    "external_id": item["id"],
                    "name": item["attributes"]["name"],
                    "artist_name": item["attributes"]["artistName"],
                    "img_url": item["attributes"]["artwork"]["url"],
                    "duration_ms": item["attributes"]["durationInMillis"],
                }
            )

    return cleaned_data
コード例 #8
0
def _get_spotify_search_results(query, formats, user):
    Collection = apps.get_model("music", "Collection")
    Track = apps.get_model("music", "Track")
    Request = apps.get_model("networking", "Request")

    formats = set(formats).intersection(
        set([Track.FORMAT_TRACK, Collection.FORMAT_ALBUM, Collection.FORMAT_PLAYLIST])
    )

    data = {
        "q": query,
        "type": ",".join(formats),
    }

    spotify_access_token = user.spotify_access_token

    response = make_request(
        Request.TYPE_GET,
        "https://api.spotify.com/v1/search",
        data=data,
        headers={
            "Authorization": f"Bearer {spotify_access_token}",
            "Content-Type": "application/json",
        },
    )
    response_json = response.json()

    data = []

    # Glue everything together
    # - - - - - - - - - - - - -
    if "albums" in response_json:
        items = response_json["albums"]["items"]
        for item in items:
            data.append(
                {
                    "format": "album",
                    "provider": "spotify",
                    "external_id": item["uri"],
                    "name": item["name"],
                    "artist_name": ", ".join([a["name"] for a in item["artists"]]),
                    "img_url": item["images"][0]["url"],
                }
            )
    if "playlists" in response_json:
        items = response_json["playlists"]["items"]
        for item in items:
            data.append(
                {
                    "format": "playlist",
                    "provider": "spotify",
                    "external_id": item["uri"],
                    "name": item["name"],
                    "artist_name": item["owner"]["display_name"],
                    "img_url": item["images"][0]["url"],
                }
            )
    if "tracks" in response_json:
        items = response_json["tracks"]["items"]
        for item in items:
            data.append(
                {
                    "format": "track",
                    "provider": "spotify",
                    "external_id": item["uri"],
                    "name": item["name"],
                    "artist_name": ", ".join([a["name"] for a in item["artists"]]),
                    "album_name": item["album"]["name"],
                    "img_url": item["album"]["images"][0]["url"],
                }
            )

    return data
コード例 #9
0
def _refresh_collection_apple_music_playlist_data(collection, user):
    CollectionListing = apps.get_model("music", "CollectionListing")
    Track = apps.get_model("music", "Track")
    Request = apps.get_model("networking", "Request")

    apple_music_token = generate_apple_music_token()
    apple_music_id = collection.external_id

    response = make_request(
        Request.TYPE_GET,
        f"https://api.music.apple.com/v1/catalog/us/playlists/{apple_music_id}",
        headers={
            "Authorization": f"Bearer {apple_music_token}",
        },
    )
    response_json = response.json()

    items = response_json["data"][0]["relationships"]["tracks"]["data"]
    data = []
    for item in items:
        data.append({
            # to be saved as Track instances
            "format": Track.FORMAT_TRACK,
            "provider": Track.PROVIDER_APPLE_MUSIC,
            "external_id": item["id"],
            "name": item["attributes"]["name"],
            "artist_name": item["attributes"]["artistName"],
            "album_name": item["attributes"]["albumName"],
            "duration_ms": item["attributes"]["durationInMillis"],
            "img_url": item["attributes"]["artwork"]["url"],
            # not saved in Track table
            "_disk_number": item["attributes"]["discNumber"],
            "_track_number": item["attributes"]["trackNumber"],
        })

    # first sort by disk number, then by track number
    data = sorted(data, key=lambda d: (d["_disk_number"], d["_track_number"]))

    tracks = []
    track_eids = []
    for track_data in data:
        tracks.append(
            Track(
                format=track_data["format"],
                provider=track_data["provider"],
                external_id=track_data["external_id"],
                name=track_data["name"],
                artist_name=track_data["artist_name"],
                album_name=track_data["album_name"],
                img_url=track_data["img_url"],
                duration_ms=track_data["duration_ms"],
            ))
        track_eids.append(track_data["external_id"])

    # create Track objects if they do not already exist
    # TODO refresh more data points
    Track.objects.bulk_create(tracks, ignore_conflicts=True)
    track_qs = Track.objects.filter(external_id__in=track_eids)

    # wipe old CollectionListing objects
    # TODO this is not ok
    cl_by_tracks_qs = CollectionListing.objects.filter(
        track__external_id__in=track_eids)
    cl_by_collection_qs = CollectionListing.objects.filter(
        collection=collection)
    now = time_util.now()
    cl_by_tracks_qs.update(deleted_at=now)
    cl_by_collection_qs.update(deleted_at=now)

    # sort tracks by order one more time
    track_map = {}
    for track in track_qs:
        track_map[track.external_id] = track

    tracks = []
    for track_eid in track_eids:
        tracks.append(track_map[track_eid])

    # create CollectionListing objects if they do not already exist
    collection_listings = []
    for idx in range(len(tracks)):
        track = tracks[idx]
        collection_listings.append(
            CollectionListing(
                track=track,
                collection=collection,
                number=idx,
            ))
    CollectionListing.objects.bulk_create(collection_listings)
コード例 #10
0
def _refresh_collection_spotify_playlist_data(collection, user):
    Track = apps.get_model("music", "Track")
    CollectionListing = apps.get_model("music", "CollectionListing")
    Request = apps.get_model("networking", "Request")

    response = make_request(
        Request.TYPE_GET,
        f"https://api.spotify.com/v1/playlists/{collection.spotify_id}",
        headers={
            "Authorization": f"Bearer {user.spotify_access_token}",
            "Content-Type": "application/json",
        },
    )
    response_json = response.json()

    # items are pre-sorted here
    items = response_json["tracks"]["items"]
    data = []
    for item in items:
        artist_names = map(lambda o: o["name"], item["track"]["artists"])
        data.append({
            "format": Track.FORMAT_TRACK,
            "provider": Track.PROVIDER_SPOTIFY,
            "external_id": item["track"]["uri"],
            "name": item["track"]["name"],
            "artist_name": ", ".join(artist_names),
            "album_name": collection.name,
            "duration_ms": item["track"]["duration_ms"],
            "img_url": item["track"]["album"]["images"][0]["url"],
        })

    tracks = []
    track_eids = []
    for track_data in data:
        tracks.append(
            Track(
                format=track_data["format"],
                provider=track_data["provider"],
                external_id=track_data["external_id"],
                name=track_data["name"],
                artist_name=track_data["artist_name"],
                album_name=track_data["album_name"],
                img_url=track_data["img_url"],
                duration_ms=track_data["duration_ms"],
            ))
        track_eids.append(track_data["external_id"])

    # create Track objects if they do not already exist
    # TODO refresh more data points
    Track.objects.bulk_create(tracks, ignore_conflicts=True)
    track_qs = Track.objects.filter(external_id__in=track_eids)

    # wipe old CollectionListing objects to force refresh playlist
    # TODO this is not ok
    cl_by_tracks_qs = CollectionListing.objects.filter(
        track__external_id__in=track_eids)
    cl_by_collection_qs = CollectionListing.objects.filter(
        collection=collection)
    now = time_util.now()
    cl_by_tracks_qs.update(deleted_at=now)
    cl_by_collection_qs.update(deleted_at=now)

    # sort tracks by order one more time
    track_map = {}
    for track in track_qs:
        track_map[track.external_id] = track

    tracks = []
    for track_eid in track_eids:
        tracks.append(track_map[track_eid])

    # create CollectionListing objects if they do not already exist
    collection_listings = []
    for idx in range(len(tracks)):
        track = tracks[idx]
        collection_listings.append(
            CollectionListing(
                track=track,
                collection=collection,
                number=idx,
            ))
    CollectionListing.objects.bulk_create(collection_listings)