Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates #175

Merged
merged 4 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ name: CI

on:
push:
branches:
- main
branches: [main]
tags:
- 'v*'
- "v*"
pull_request:
branches: ['*']
branches: ["*"]

workflow_dispatch:

Expand Down Expand Up @@ -35,13 +34,13 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
node-version: 22
registry-url: "https://registry.npmjs.org"

- name: Install pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false

- name: Get pnpm store directory
Expand All @@ -53,7 +52,7 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
key: "${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}"
restore-keys: |
${{ runner.os }}-pnpm-store-

Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,17 @@ Save the device selection.
**play** `boolean`
Control the player's status.

**preloadData** `boolean`
Preload the track data before playing.

**showSaveIcon** `boolean` ▶︎ false
Display a Favorite button. It needs additional scopes in your token.

**styles** `object`
Customize the player's appearance. Check `StylesOptions` in the [types](src/types/common.ts).

**syncExternalDevice** `boolean` ▶︎ false
If there are no URIs and an external device is playing, use the external player context.
Use the external player context if there are no URIs and an external device is playing.

**syncExternalDeviceInterval** `number` ▶︎ 5
The time in seconds that the player will sync with external devices.
Expand All @@ -252,12 +255,24 @@ import { spotifyApi } from 'react-spotify-web-playback';

**checkTracksStatus(token: string, tracks: string | string[]): Promise\<boolean[]>**

**getAlbumTracks(token: string, id: string): Promise\<SpotifyApi.AlbumTracksResponse>**

**getArtistTopTracks(token: string, id: string): Promise\<SpotifyApi.ArtistsTopTracksResponse>**

**getDevices(token: string): Promise\<SpotifyApi.UserDevicesResponse>**

**getPlaybackState(token: string): Promise\<SpotifyApi.CurrentlyPlayingObject | null>**

**getPlaylistTracks(token: string, id: string): Promise\<SpotifyApi.PlaylistTrackResponse>**

**getQueue(token: string): Promise\<SpotifyApi.UsersQueueResponse>**

**getShow(token: string, id: string): Promise\<SpotifyApi.ShowObjectFull>**

**getShowEpisodes(token: string, id: string, offset = 0): Promise\<SpotifyApi.ShowEpisodesResponse>**

**getTrack(token: string, id: string): Promise\<SpotifyApi.TrackObjectFull>**

**pause(token: string, deviceId?: string): Promise\<void>**

**play(token: string, options: SpotifyPlayOptions): Promise\<void>**
Expand Down Expand Up @@ -293,7 +308,7 @@ interface SpotifyPlayOptions {

You can customize the UI with a `styles` prop.
If you want a transparent player, you can use `bgColor: 'transparent'`.
Check all the available options [here](src/types/common.ts#L188).
Check all the available options [here](src/types/common.ts#L195).

```tsx
<SpotifyWebPlayer
Expand All @@ -310,7 +325,8 @@ Check all the available options [here](src/types/common.ts#L188).
/>
```

![rswp-styles](https://gilbarbara.com/files/rswp-styles-e4060ddf.png)
![rswp-styles](https://files.gilbarbara.dev/media/rswp-v2.png)


## Issues

Expand Down
26 changes: 13 additions & 13 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@
"keywords": [],
"main": "src/index.tsx",
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@gilbarbara/components": "^0.11.4",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@gilbarbara/hooks": "^0.8.2",
"@gilbarbara/components": "^0.14.5",
"@gilbarbara/cookies": "^1.0.1",
"@gilbarbara/eslint-config": "^0.7.5",
"@gilbarbara/helpers": "^0.9.2",
"@gilbarbara/eslint-config": "^0.8.2",
"@gilbarbara/helpers": "^0.9.4",
"@gilbarbara/prettier-config": "^1.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "^5.0.1",
"react-spotify-web-playback": "latest",
"react-use": "^17.5.0"
"react-spotify-web-playback": "latest"
},
"devDependencies": {
"@types/node": "20.11.30",
"@types/react": "18.2.73",
"@types/react-dom": "18.2.22",
"typescript": "5.4.3"
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"typescript": "5.6.3"
},
"scripts": {
"start": "react-scripts start",
Expand Down
Binary file modified demo/public/favicon.ico
Binary file not shown.
48 changes: 34 additions & 14 deletions demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import SpotifyWebPlayer, {
STATUS,
StylesProps,
TYPE,
Type,
} from 'react-spotify-web-playback';
import { useEffectOnce, useSetState } from 'react-use';
import {
Anchor,
Box,
Button,
ComponentWrapper,
Container,
Flex,
FormElementWrapper,
Grid,
H1,
H4,
Expand All @@ -28,6 +29,7 @@ import {
Toggle,
} from '@gilbarbara/components';
import { request } from '@gilbarbara/helpers';
import { useEffectOnce, useSetState } from '@gilbarbara/hooks';

import GlobalStyles from './components/GlobalStyles';
import Player from './components/Player';
Expand Down Expand Up @@ -64,6 +66,7 @@ const baseURIs = {
album: 'spotify:album:0WLIcGHr0nLyKJpMirAS17',
artist: 'spotify:artist:4oLeXFyACqeem2VImYeBFe',
playlist: 'spotify:playlist:1Zr2FUPeD5hYJTGbTDSQs4',
show: 'spotify:show:4kYCRYJ3yK5DQbP5tbfZby',
tracks: [
// Boogie
// 'spotify:track:3zYpRGnnoegSpt3SguSo3W',
Expand Down Expand Up @@ -97,6 +100,7 @@ function App() {

const code = new URLSearchParams(window.location.search).get('code');
const credentials = getCredentials();

const [
{
accessToken,
Expand Down Expand Up @@ -159,7 +163,7 @@ function App() {
(event: FormEvent) => {
event.preventDefault();

if (URIsInput && URIsInput.current) {
if (URIsInput?.current) {
setState({ URIs: parseURIs(URIsInput.current.value) });
}
},
Expand All @@ -178,7 +182,7 @@ function App() {

setState({ isPlaying: true, URIs: parseURIs(uris) });

if (URIsInput && URIsInput.current) {
if (URIsInput?.current) {
URIsInput.current.value = uris;
}
},
Expand All @@ -202,7 +206,7 @@ function App() {
});
}

if (type === TYPE.TRACK) {
if (([TYPE.PRELOAD, TYPE.TRACK] as Array<Type>).includes(type)) {
const trackStyles = await request<StylesProps>(
`https://scripts.gilbarbara.dev/api/getImagePlayerStyles?url=${track.image}`,
);
Expand Down Expand Up @@ -238,14 +242,14 @@ function App() {

const content: Record<string, ReactNode> = {
connect: (
<Box flexBox justify="center" maxWidth={320} mx="auto" width="100%">
<Flex justify="center" maxWidth={320} mx="auto" width="100%">
<Anchor href={getAuthorizeUrl()}>
<Button size="lg">
<Icon mr="sm" name="spotify" size={24} />
<span>Connect</span>
</Button>
</Anchor>
</Box>
</Flex>
),
};

Expand All @@ -262,8 +266,8 @@ function App() {
content.main = (
<>
<Box as="form" maxWidth={320} mx="auto" onSubmit={handleSubmitURIs} width="100%">
<ComponentWrapper
suffix={
<FormElementWrapper
endContent={
<Button
shape="round"
style={{ borderBottomLeftRadius: 0, borderTopLeftRadius: 0 }}
Expand All @@ -281,7 +285,7 @@ function App() {
placeholder="Enter a Spotify URI"
suffixSpacing={48}
/>
</ComponentWrapper>
</FormElementWrapper>
</Box>
<Grid gap={20} maxWidth={320} mt="xl" mx="auto" templateColumns="repeat(2, 1fr)">
<Button data-uris={baseURIs.artist} onClick={handleClickURIs} size="sm">
Expand Down Expand Up @@ -314,24 +318,24 @@ function App() {
value={layout}
/>
<H4 mt="md">Props</H4>
<Spacer distribution="center" gapVertical="md" mx="auto">
<Spacer distribution="center" gap="md" mx="auto">
<Toggle
checked={hideAttribution}
label="Hide Attribution"
name="hideAttribution"
onClick={() => setState({ hideAttribution: !hideAttribution })}
onToggle={() => setState({ hideAttribution: !hideAttribution })}
/>
<Toggle
checked={inlineVolume}
label="Inline Volume"
name="inlineVolume"
onClick={() => setState({ inlineVolume: !inlineVolume })}
onToggle={() => setState({ inlineVolume: !inlineVolume })}
/>
<Toggle
checked={transparent}
label="Transparent"
name="transparent"
onClick={() => setState({ transparent: !transparent })}
onToggle={() => setState({ transparent: !transparent })}
/>
</Spacer>
</Box>
Expand All @@ -348,13 +352,29 @@ function App() {
),
rightButton: <RepeatButton disabled={!isActive} repeat={repeat} token={accessToken} />,
}}
getOAuthToken={async callback => {
if ((credentials.expiresAt ?? 0) < Math.round(Date.now() / 1000)) {
const newCredentials = await refreshCredentials(refreshToken);

setCredentials(newCredentials);
setState({
accessToken: newCredentials.accessToken,
refreshToken: newCredentials.refreshToken,
});

callback(newCredentials.accessToken);
} else {
callback(accessToken);
}
}}
getPlayer={getPlayer}
hideAttribution={hideAttribution}
initialVolume={100}
inlineVolume={inlineVolume}
layout={layout}
persistDeviceSelection
play={isPlaying}
preloadData
showSaveIcon
styles={transparent ? { ...styles, bgColor: 'transparent' } : styles}
syncExternalDevice
Expand Down
6 changes: 3 additions & 3 deletions demo/src/components/RepeatButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ComponentProps, useCallback } from 'react';
import { RepeatState, spotifyApi } from 'react-spotify-web-playback';
import { BoxInline, ButtonUnstyled, Icon } from '@gilbarbara/components';
import { ButtonUnstyled, FlexInline, Icon } from '@gilbarbara/components';

export default function RepeatButton({
repeat,
Expand Down Expand Up @@ -41,7 +41,7 @@ export default function RepeatButton({
width={32}
{...rest}
>
<BoxInline as="span" position="relative">
<FlexInline as="span" position="relative">
<Icon name="repeat" size={24} title={null} />
{repeat !== 'off' && (
<span
Expand All @@ -57,7 +57,7 @@ export default function RepeatButton({
{repeat === 'track' ? '1' : 'all'}
</span>
)}
</BoxInline>
</FlexInline>
</ButtonUnstyled>
);
}
14 changes: 7 additions & 7 deletions demo/src/components/ShuffleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ComponentProps, useCallback } from 'react';
import { spotifyApi } from 'react-spotify-web-playback';
import { BoxInline, ButtonUnstyled, Icon } from '@gilbarbara/components';
import { ButtonUnstyled, FlexInline, Icon } from '@gilbarbara/components';

export default function ShuffleButton({
shuffle,
token,
...rest
}: Omit<ComponentProps<typeof ButtonUnstyled>, 'children'> & {
shuffle,
token,
...rest
}: Omit<ComponentProps<typeof ButtonUnstyled>, 'children'> & {
shuffle: boolean;
token: string;
}) {
Expand All @@ -23,7 +23,7 @@ export default function ShuffleButton({
width={32}
{...rest}
>
<BoxInline as="span" position="relative">
<FlexInline position="relative">
<Icon name="shuffle" size={20} title={null} />
{shuffle && (
<span
Expand All @@ -39,7 +39,7 @@ export default function ShuffleButton({
</span>
)}
</BoxInline>
</FlexInline>
</ButtonUnstyled>
);
}
6 changes: 3 additions & 3 deletions demo/src/modules/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getCookie, removeCookie, setCookie } from '@gilbarbara/cookies';
import { request } from '@gilbarbara/helpers';
import { MONTH, request } from '@gilbarbara/helpers';

import { SpotifyCredentials } from '../types';

Expand Down Expand Up @@ -49,7 +49,7 @@ export function getCredentials() {
}

export function setCredentials(credentials: SpotifyCredentials) {
setCookie(COOKIE_NAME, JSON.stringify(credentials));
setCookie(COOKIE_NAME, JSON.stringify(credentials), { expires: MONTH * 6 });
}

export async function login(code: string) {
Expand Down Expand Up @@ -79,7 +79,7 @@ export function parseURIs(input: string): string[] {
export function validateURI(input: string): boolean {
let isValid = false;

if (input && input.includes(':')) {
if (input?.includes(':')) {
const [key, type, id] = input.split(':');

if (key && type && type !== 'user' && id && id.length === 22) {
Expand Down
Loading
Loading