Skip to content

Commit

Permalink
add spotify
Browse files Browse the repository at this point in the history
  • Loading branch information
RuslanUC committed Mar 10, 2024
1 parent d09bb09 commit 6a18369
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 5 deletions.
2 changes: 1 addition & 1 deletion STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
- [ ] Twitter
- [ ] eBay
- [ ] PlayStation Network
- [ ] Spotify
- [x] Spotify
- [ ] Xbox
- [ ] Battle.net
- [ ] Epic Games
Expand Down
4 changes: 4 additions & 0 deletions config.example.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,8 @@
"client_id": None,
"client_secret": None,
},
"spotify": {
"client_id": None,
"client_secret": None,
},
}
3 changes: 2 additions & 1 deletion yepcord/rest_api/models/users_me.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,5 @@ def validate_handshake_token(cls, value: str) -> str:


class EditConnection(BaseModel):
visibility: bool
visibility: Optional[bool] = None
show_activity: Optional[bool] = None
13 changes: 12 additions & 1 deletion yepcord/rest_api/routes/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
from ..models.connections import ConnectionCallback
from ..y_blueprint import YBlueprint
from ...gateway.events import UserConnectionsUpdate
from ...yepcord.classes.connections import ConnectionGithub, ConnectionReddit, ConnectionTwitch, BaseConnection
from ...yepcord.classes.connections import ConnectionGithub, ConnectionReddit, ConnectionTwitch, BaseConnection, \
ConnectionSpotify
from ...yepcord.ctx import getGw
from ...yepcord.models import User, ConnectedAccount

Expand Down Expand Up @@ -74,3 +75,13 @@ async def connection_twitch_authorize(user: User = DepUser):
@connections.post("/twitch/callback", body_cls=ConnectionCallback)
async def connection_twitch_callback(data: ConnectionCallback):
return await unified_callback(ConnectionTwitch, data)


@connections.get("/spotify/authorize")
async def connection_spotify_authorize(user: User = DepUser):
return {"url": await ConnectionSpotify.authorize_url(user)}


@connections.post("/spotify/callback", body_cls=ConnectionCallback)
async def connection_spotify_callback(data: ConnectionCallback):
return await unified_callback(ConnectionSpotify, data, "display_name")
4 changes: 2 additions & 2 deletions yepcord/rest_api/routes/users_me.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ async def get_connections(user: User = DepUser):

@users_me.patch("/connections/<string:service>/<string:ext_id>", body_cls=EditConnection)
async def edit_connection(service: str, ext_id: str, data: EditConnection, user: User = DepUser):
if service not in {"github"}:
if service not in Config.CONNECTIONS:
raise InvalidDataErr(400, Errors.make(50035, {"provider_id": {
"code": "ENUM_TYPE_COERCE", "message": f"Value '{service}' is not a valid enum value."
}}))
Expand All @@ -209,7 +209,7 @@ async def edit_connection(service: str, ext_id: str, data: EditConnection, user:
if connection is None:
raise InvalidDataErr(404, Errors.make(10017))

await connection.update(**data.model_dump())
await connection.update(**data.model_dump(exclude_none=True))

await getGw().dispatch(UserConnectionsUpdate(connection), user_ids=[user.id])
return connection.ds_json()
Expand Down
24 changes: 24 additions & 0 deletions yepcord/yepcord/classes/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,27 @@ def user_info_req(cls, access_token: str) -> tuple[str, dict]:
@classmethod
async def get_user_info(cls, access_token: str) -> dict:
return (await super(cls, ConnectionTwitch).get_user_info(access_token))["data"][0]


class ConnectionSpotify(BaseConnection):
SERVICE_NAME = "spotify"
AUTHORIZE_URL = "https://accounts.spotify.com/authorize"
TOKEN_URL = "https://accounts.spotify.com/api/token"
USER_URL = "https://api.spotify.com/v1/me"
SCOPE: list[str] = ["user-read-private", "user-read-playback-state", "user-modify-playback-state",
"user-read-currently-playing"]

@classmethod
async def authorize_url(cls, user: User) -> str:
return f"{await super(cls, ConnectionSpotify).authorize_url(user)}&response_type=code"

@classmethod
def exchange_code_req(cls, code: str, settings: dict[str, str]) -> tuple[str, dict]:
callback_url = quote(f"https://{Config.PUBLIC_HOST}/connections/spotify/callback", safe="")
kwargs = {
"auth": (settings["client_id"], settings["client_secret"]),
"headers": {"Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"},
"content": f"grant_type=authorization_code&code={code}&redirect_uri={callback_url}",
}

return cls.TOKEN_URL, kwargs
1 change: 1 addition & 0 deletions yepcord/yepcord/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class ConfigConnections(BaseModel):
github: ConfigConnectionBase = Field(default_factory=ConfigConnectionBase)
reddit: ConfigConnectionBase = Field(default_factory=ConfigConnectionBase)
twitch: ConfigConnectionBase = Field(default_factory=ConfigConnectionBase)
spotify: ConfigConnectionBase = Field(default_factory=ConfigConnectionBase)


class ConfigModel(BaseModel):
Expand Down

0 comments on commit 6a18369

Please sign in to comment.