spotify-now-playing-card 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bojan Jagetic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # Spotify Now Playing Card
2
+
3
+ A beautiful, customizable React component to display your currently playing Spotify track. Perfect for personal websites, portfolios, and blogs.
4
+
5
+ ## Features
6
+
7
+ - 🎵 Displays currently playing track from Spotify
8
+ - 🎨 Fully customizable styling
9
+ - âš¡ Built with SWR for efficient data fetching
10
+ - 📱 Responsive design
11
+ - 🔄 Auto-refresh with configurable interval
12
+ - 🎯 Framework agnostic (works with Next.js, Create React App, etc.)
13
+ - 📘 Written in TypeScript with full type definitions
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install spotify-now-playing-card
19
+ # or
20
+ yarn add spotify-now-playing-card
21
+ # or
22
+ pnpm add spotify-now-playing-card
23
+ ```
24
+
25
+ ## Prerequisites
26
+
27
+ You need to set up a Spotify API endpoint that returns the currently playing track data. The component expects the API to return JSON in this format:
28
+
29
+ ```json
30
+ {
31
+ "isPlaying": true,
32
+ "title": "Song Title",
33
+ "artist": "Artist Name",
34
+ "album": "Album Name",
35
+ "albumImageUrl": "https://...",
36
+ "songUrl": "https://open.spotify.com/track/..."
37
+ }
38
+ ```
39
+
40
+ When not playing, the API should return:
41
+ ```json
42
+ {
43
+ "isPlaying": false
44
+ }
45
+ ```
46
+
47
+ ### Setting up Spotify API
48
+
49
+ 1. Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)
50
+ 2. Create a new app
51
+ 3. Get your `CLIENT_ID` and `CLIENT_SECRET`
52
+ 4. Set redirect URI (e.g., `http://localhost:3000/api/spotify/callback`)
53
+ 5. Get your refresh token (you can use tools like [this](https://github.com/spotify/web-api-auth-examples))
54
+
55
+ ### Example API Endpoint (Next.js)
56
+
57
+ Create `pages/api/spotify.js`:
58
+
59
+ ```javascript
60
+ import querystring from 'querystring'
61
+ import axios from 'axios'
62
+
63
+ const {
64
+ SPOTIFY_CLIENT_ID: client_id,
65
+ SPOTIFY_CLIENT_SECRET: client_secret,
66
+ SPOTIFY_REFRESH_TOKEN: refresh_token
67
+ } = process.env
68
+
69
+ const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64')
70
+ const NOW_PLAYING_ENDPOINT = 'https://api.spotify.com/v1/me/player/currently-playing'
71
+ const TOKEN_ENDPOINT = 'https://accounts.spotify.com/api/token'
72
+
73
+ const getAccessToken = async () => {
74
+ const response = await axios.post(
75
+ TOKEN_ENDPOINT,
76
+ querystring.stringify({
77
+ grant_type: 'refresh_token',
78
+ refresh_token
79
+ }),
80
+ {
81
+ headers: {
82
+ Authorization: `Basic ${basic}`,
83
+ 'Content-Type': 'application/x-www-form-urlencoded'
84
+ }
85
+ }
86
+ )
87
+ return response.data
88
+ }
89
+
90
+ export default async function handler(req, res) {
91
+ try {
92
+ const { access_token } = await getAccessToken()
93
+ const response = await axios.get(NOW_PLAYING_ENDPOINT, {
94
+ headers: {
95
+ Authorization: `Bearer ${access_token}`
96
+ }
97
+ })
98
+
99
+ if (
100
+ response.status === 204 ||
101
+ response.status > 400 ||
102
+ (response.data && response.data.currently_playing_type !== 'track')
103
+ ) {
104
+ return res.status(200).json({ isPlaying: false })
105
+ }
106
+
107
+ const data = {
108
+ isPlaying: response.data.is_playing,
109
+ title: response.data.item.name,
110
+ album: response.data.item.album.name,
111
+ artist: response.data.item.album.artists.map((artist) => artist.name).join(', '),
112
+ albumImageUrl: response.data.item.album.images[0].url,
113
+ songUrl: response.data.item.external_urls.spotify
114
+ }
115
+
116
+ res.status(200).json(data)
117
+ } catch (error) {
118
+ res.status(200).json({ isPlaying: false })
119
+ }
120
+ }
121
+ ```
122
+
123
+ ## Usage
124
+
125
+ ### Basic Usage
126
+
127
+ ```jsx
128
+ import { SpotifyCard } from 'spotify-now-playing-card'
129
+
130
+ function App() {
131
+ return <SpotifyCard apiUrl="/api/spotify" />
132
+ }
133
+ ```
134
+
135
+ ### TypeScript Usage
136
+
137
+ The package includes full TypeScript definitions:
138
+
139
+ ```tsx
140
+ import { SpotifyCard, SpotifyCardProps } from 'spotify-now-playing-card'
141
+
142
+ const MyComponent: React.FC = () => {
143
+ const cardProps: SpotifyCardProps = {
144
+ apiUrl: '/api/spotify',
145
+ showAlbum: true,
146
+ refreshInterval: 30000
147
+ }
148
+
149
+ return <SpotifyCard {...cardProps} />
150
+ }
151
+ ```
152
+
153
+ ### With Custom Styling
154
+
155
+ ```jsx
156
+ import { SpotifyCard } from 'spotify-now-playing-card'
157
+
158
+ function App() {
159
+ return (
160
+ <SpotifyCard
161
+ apiUrl="/api/spotify"
162
+ className="my-custom-class"
163
+ styles={{
164
+ container: "bg-gray-900 rounded-xl",
165
+ title: "text-white text-lg",
166
+ artist: "text-gray-400"
167
+ }}
168
+ />
169
+ )
170
+ }
171
+ ```
172
+
173
+ ### All Props
174
+
175
+ | Prop | Type | Default | Description |
176
+ |------|------|---------|-------------|
177
+ | `apiUrl` | `string` | `'/api/spotify'` | API endpoint URL that returns Spotify data |
178
+ | `fallbackUrl` | `string` | `'https://open.spotify.com'` | URL to redirect when not playing |
179
+ | `className` | `string` | `''` | Additional CSS classes for container |
180
+ | `styles` | `object` | `{}` | Custom style overrides for different elements |
181
+ | `showAlbum` | `boolean` | `true` | Whether to show album name |
182
+ | `notPlayingText` | `string` | `'Currently not listening'` | Text when not playing |
183
+ | `refreshInterval` | `number` | `30000` | Auto-refresh interval in milliseconds |
184
+
185
+ ### Styling
186
+
187
+ The component uses Tailwind CSS classes by default. Make sure you have Tailwind CSS installed and configured in your project.
188
+
189
+ If you're not using Tailwind, you can override all styles using the `styles` prop or `className` prop.
190
+
191
+ ## Dependencies
192
+
193
+ - `react` (>=16.8.0)
194
+ - `react-dom` (>=16.8.0)
195
+ - `axios` (for API calls)
196
+ - `swr` (for data fetching)
197
+ - `react-icons` (for Spotify icon)
198
+
199
+ ## License
200
+
201
+ MIT
202
+
203
+ ## Contributing
204
+
205
+ Contributions are welcome! Please feel free to submit a Pull Request.
206
+
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ export interface SpotifyData {
3
+ isPlaying: boolean;
4
+ title?: string;
5
+ artist?: string;
6
+ album?: string;
7
+ albumImageUrl?: string;
8
+ songUrl?: string;
9
+ }
10
+ export interface SpotifyCardStyles {
11
+ container?: string;
12
+ link?: string;
13
+ image?: string;
14
+ title?: string;
15
+ artist?: string;
16
+ album?: string;
17
+ icon?: string;
18
+ }
19
+ export interface SpotifyCardProps {
20
+ /** The API endpoint URL that returns Spotify data */
21
+ apiUrl?: string;
22
+ /** URL to redirect when not playing (default: Spotify profile) */
23
+ fallbackUrl?: string;
24
+ /** Additional CSS classes for the card container */
25
+ className?: string;
26
+ /** Custom style overrides for different elements */
27
+ styles?: SpotifyCardStyles;
28
+ /** Whether to show album name (default: true) */
29
+ showAlbum?: boolean;
30
+ /** Text to show when not playing (default: "Currently not listening") */
31
+ notPlayingText?: string;
32
+ /** Auto-refresh interval in milliseconds (default: 30000) */
33
+ refreshInterval?: number;
34
+ /** Additional props to pass to the container div */
35
+ [key: string]: any;
36
+ }
37
+ /**
38
+ * SpotifyCard - A React component to display currently playing Spotify track
39
+ */
40
+ declare const SpotifyCard: React.FC<SpotifyCardProps>;
41
+ export default SpotifyCard;
42
+ //# sourceMappingURL=SpotifyCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpotifyCard.d.ts","sourceRoot":"","sources":["../src/SpotifyCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oDAAoD;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;GAEG;AACH,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAsF3C,CAAA;AAED,eAAe,WAAW,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { default as SpotifyCard } from './SpotifyCard';
2
+ export { default } from './SpotifyCard';
3
+ export type { SpotifyCardProps, SpotifyCardStyles, SpotifyData } from './SpotifyCard';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,44 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import axios from 'axios';
3
+ import { SiSpotify } from 'react-icons/si';
4
+ import useSWR from 'swr';
5
+
6
+ const fetcher = (url) => axios.get(url).then(res => res.data);
7
+ /**
8
+ * SpotifyCard - A React component to display currently playing Spotify track
9
+ */
10
+ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 30000, ...props }) => {
11
+ const { data, error } = useSWR(apiUrl, fetcher, {
12
+ refreshInterval: refreshInterval,
13
+ revalidateOnFocus: true
14
+ });
15
+ if (error) {
16
+ console.error('SpotifyCard error:', error);
17
+ }
18
+ const defaultStyles = {
19
+ container: 'text-slate-400 border border-neutral-800 rounded-lg w-full mx-5 my-2',
20
+ link: 'relative flex items-center space-x-2 py-4 pl-2 transition-shadow hover:shadow-md',
21
+ image: 'w-14 shadow-sm',
22
+ title: 'font-bold text-md w-48 lg:w-72 truncate',
23
+ artist: 'text-sm font-semibold',
24
+ album: 'text-xs font-semibold w-48 lg:w-72 truncate',
25
+ icon: 'absolute right-1.5 top-1.5'
26
+ };
27
+ const mergedStyles = {
28
+ container: `${defaultStyles.container} ${styles.container || ''} ${className}`,
29
+ link: `${defaultStyles.link} ${styles.link || ''}`,
30
+ image: `${defaultStyles.image} ${styles.image || ''}`,
31
+ title: `${defaultStyles.title} ${styles.title || ''}`,
32
+ artist: `${defaultStyles.artist} ${styles.artist || ''}`,
33
+ album: `${defaultStyles.album} ${styles.album || ''}`,
34
+ icon: `${defaultStyles.icon} ${styles.icon || ''}`
35
+ };
36
+ const isPlaying = data?.isPlaying;
37
+ const titleColor = isPlaying
38
+ ? 'text-transparent bg-clip-text bg-gradient-to-r from-violet-500 via-blue-500 to-emerald-500'
39
+ : '';
40
+ return (jsx("div", { className: mergedStyles.container, ...props, children: jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsx("div", { className: 'w-15', children: isPlaying ? (jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsx(SiSpotify, { size: 30, color: '#1ED760' })) }), jsxs("div", { className: 'flex-1', children: [jsx("p", { className: `${mergedStyles.title} ${titleColor}`, children: isPlaying ? data?.title : notPlayingText }), jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsx("div", { className: mergedStyles.icon, children: jsx(SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
41
+ };
42
+
43
+ export { SpotifyCard, SpotifyCard as default };
44
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var axios = require('axios');
7
+ var si = require('react-icons/si');
8
+ var useSWR = require('swr');
9
+
10
+ const fetcher = (url) => axios.get(url).then(res => res.data);
11
+ /**
12
+ * SpotifyCard - A React component to display currently playing Spotify track
13
+ */
14
+ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 30000, ...props }) => {
15
+ const { data, error } = useSWR(apiUrl, fetcher, {
16
+ refreshInterval: refreshInterval,
17
+ revalidateOnFocus: true
18
+ });
19
+ if (error) {
20
+ console.error('SpotifyCard error:', error);
21
+ }
22
+ const defaultStyles = {
23
+ container: 'text-slate-400 border border-neutral-800 rounded-lg w-full mx-5 my-2',
24
+ link: 'relative flex items-center space-x-2 py-4 pl-2 transition-shadow hover:shadow-md',
25
+ image: 'w-14 shadow-sm',
26
+ title: 'font-bold text-md w-48 lg:w-72 truncate',
27
+ artist: 'text-sm font-semibold',
28
+ album: 'text-xs font-semibold w-48 lg:w-72 truncate',
29
+ icon: 'absolute right-1.5 top-1.5'
30
+ };
31
+ const mergedStyles = {
32
+ container: `${defaultStyles.container} ${styles.container || ''} ${className}`,
33
+ link: `${defaultStyles.link} ${styles.link || ''}`,
34
+ image: `${defaultStyles.image} ${styles.image || ''}`,
35
+ title: `${defaultStyles.title} ${styles.title || ''}`,
36
+ artist: `${defaultStyles.artist} ${styles.artist || ''}`,
37
+ album: `${defaultStyles.album} ${styles.album || ''}`,
38
+ icon: `${defaultStyles.icon} ${styles.icon || ''}`
39
+ };
40
+ const isPlaying = data?.isPlaying;
41
+ const titleColor = isPlaying
42
+ ? 'text-transparent bg-clip-text bg-gradient-to-r from-violet-500 via-blue-500 to-emerald-500'
43
+ : '';
44
+ return (jsxRuntime.jsx("div", { className: mergedStyles.container, ...props, children: jsxRuntime.jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsxRuntime.jsx("div", { className: 'w-15', children: isPlaying ? (jsxRuntime.jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsxRuntime.jsx(si.SiSpotify, { size: 30, color: '#1ED760' })) }), jsxRuntime.jsxs("div", { className: 'flex-1', children: [jsxRuntime.jsx("p", { className: `${mergedStyles.title} ${titleColor}`, children: isPlaying ? data?.title : notPlayingText }), jsxRuntime.jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxRuntime.jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsxRuntime.jsx("div", { className: mergedStyles.icon, children: jsxRuntime.jsx(si.SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
45
+ };
46
+
47
+ exports.SpotifyCard = SpotifyCard;
48
+ exports.default = SpotifyCard;
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs","SiSpotify"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "spotify-now-playing-card",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "A beautiful React component to display your currently playing Spotify track",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "rollup -c",
15
+ "dev": "rollup -c -w",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "spotify",
20
+ "react",
21
+ "component",
22
+ "now-playing",
23
+ "music",
24
+ "card",
25
+ "widget"
26
+ ],
27
+ "author": "Bojan Jagetic",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/yourusername/spotify-now-playing-card.git"
32
+ },
33
+ "peerDependencies": {
34
+ "react": ">=16.8.0",
35
+ "react-dom": ">=16.8.0"
36
+ },
37
+ "dependencies": {
38
+ "axios": "^1.6.4",
39
+ "react-icons": "^4.3.1",
40
+ "swr": "^1.3.0"
41
+ },
42
+ "devDependencies": {
43
+ "@rollup/plugin-commonjs": "^25.0.7",
44
+ "@rollup/plugin-node-resolve": "^15.2.3",
45
+ "@rollup/plugin-typescript": "^11.1.5",
46
+ "@types/react": "^18.2.43",
47
+ "@types/react-dom": "^18.2.17",
48
+ "react": "^18.2.0",
49
+ "react-dom": "^18.2.0",
50
+ "rollup": "^4.6.1",
51
+ "tslib": "^2.8.1",
52
+ "typescript": "^5.3.3"
53
+ }
54
+ }