nocopyrightsounds-widget 1.1.0 → 1.2.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/README.md CHANGED
@@ -1,20 +1,115 @@
1
- # NoCopyrightSounds Widget 🎵
1
+ # 🎧 NoCopyrightSounds (NCS) Web Widget
2
2
 
3
- Un module persistant et personnalisable pour intégrer de la musique NCS sur n'importe quel site web.
3
+ [![NPM Version](https://img.shields.io/npm/v/nocopyrightsounds-widget.svg?style=flat-square&color=1DB954)](https://www.npmjs.com/package/nocopyrightsounds-widget)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
4
5
 
5
- ## Installation
6
+ Un lecteur musical flottant, élégant et hautement personnalisable pour intégrer facilement les musiques libres de droits de **NoCopyrightSounds** à n'importe quel site web.
6
7
 
8
+ Conçu pour les développeurs modernes : léger, persistant entre les changements de pages, et entièrement paramétrable via JavaScript et CSS.
9
+
10
+ ![NCS Widget Preview](https://raw.githubusercontent.com/floriangobin/nocopyrightsounds-widget/main/preview.png) *(Ajoutez une capture d'écran de votre widget dans votre dépôt GitHub et remplacez ce lien plus tard !)*
11
+
12
+ ---
13
+
14
+ ## ✨ Fonctionnalités
15
+
16
+ * ⚡ **Zéro Latence :** Algorithme de préchargement (buffering) intelligent en arrière-plan pour des transitions instantanées entre les morceaux.
17
+ * 💾 **Persistance d'état :** Mémorise la piste en cours, le volume, la progression et l'état d'ouverture du widget d'une page à l'autre via `localStorage`.
18
+ * 🎨 **Design Premium :** Support natif des modes clair/sombre, personnalisation des couleurs, et effet **Glassmorphism** (verre dépoli).
19
+ * 🎛️ **Contrôles Complets :** Boutons Suivant/Précédent avec historique, contrôle du volume, Mute, et barre de progression cliquable.
20
+ * 🎵 **Catalogue Complet :** Navigation aléatoire intelligente parmi les 60+ genres historiques de NCS.
21
+ * 👁️ **UI Modulaire :** Possibilité de masquer des éléments (téléchargement, visualizer) pour un rendu minimaliste.
22
+
23
+ ---
24
+
25
+ ## 📦 Installation
26
+
27
+ ### Via NPM (Recommandé pour React, Vue, Angular...)
7
28
  \`\`\`bash
8
29
  npm install nocopyrightsounds-widget
9
30
  \`\`\`
10
31
 
11
- ## Utilisation
32
+ ### Via CDN (Pour les sites HTML classiques / Vanilla JS)
33
+ \`\`\`html
34
+ <script type="module">
35
+ import NCSWidget from 'https://cdn.jsdelivr.net/npm/nocopyrightsounds-widget@latest/src/index.js';
36
+ </script>
37
+ \`\`\`
12
38
 
13
- \`\`\`javascript
14
- import NCSWidget from 'nocopyrightsounds-widget';
39
+ ---
40
+
41
+ ## 🚀 Utilisation Rapide
42
+
43
+ ### Exemple basique
44
+ \`\`\`html
45
+ <script type="module">
46
+ import NCSWidget from 'https://cdn.jsdelivr.net/npm/nocopyrightsounds-widget@latest/src/index.js';
47
+ const player = new NCSWidget();
48
+ </script>
49
+ \`\`\`
15
50
 
51
+ ### Exemple Avancé (Toutes les options)
52
+ \`\`\`javascript
16
53
  const widget = new NCSWidget({
17
- position: 'bottom-right', // 'bottom-left', 'top-right', 'top-left'
18
- apiUrl: 'https://ncs-backend-api.onrender.com' // L'URL de votre API
54
+ position: 'bottom-left', // 'bottom-right', 'top-left', 'top-right'
55
+ offset: '30px', // Distance par rapport au bord de l'écran
56
+ theme: 'dark', // 'dark' ou 'light'
57
+ primaryColor: '#9d4edd', // Couleur principale (ex: Violet)
58
+ glassmorphism: true, // Active l'effet de transparence floutée
59
+ borderRadius: '12px', // Arrondi de la fenêtre
60
+ fontFamily: "'Courier New', monospace", // Police d'écriture personnalisée
61
+ defaultGenre: '10', // Démarre sur la House (ID: 10)
62
+ startVolume: 0.3, // Volume initial à 30%
63
+ hideDownload: true, // Cache le bouton de téléchargement
64
+ hideVisualizer: false, // Garde l'animation sonore
65
+ autoOpen: true // Ouvre le lecteur automatiquement à la 1ère visite
19
66
  });
20
- \`\`\`
67
+ \`\`\`
68
+
69
+ ---
70
+
71
+ ## ⚙️ Configuration Détaillée (Options)
72
+
73
+ | Option | Type | Défaut | Description |
74
+ | :--- | :--- | :--- | :--- |
75
+ | \`position\` | String | \`'bottom-right'\` | Position à l'écran (\`bottom-right\`, \`bottom-left\`, \`top-right\`, \`top-left\`). |
76
+ | \`offset\` | String | \`'25px'\` | Marge par rapport au bord de l'écran. |
77
+ | \`theme\` | String | \`'dark'\` | Thème de base de l'interface (\`'dark'\` ou \`'light'\`). |
78
+ | \`primaryColor\` | String | \`'#1DB954'\` | Couleur principale (Bouton d'ouverture, slider, visualizer). |
79
+ | \`glassmorphism\`| Boolean | \`false\` | Active un fond semi-transparent avec flou d'arrière-plan (backdrop-filter). |
80
+ | \`borderRadius\` | String | \`'16px'\` | Rayon des bordures du lecteur étendu. |
81
+ | \`fontFamily\` | String | \`'system-ui...'\`| Typographie utilisée dans tout le widget. |
82
+ | \`hideDownload\` | Boolean | \`false\` | Masque l'icône de téléchargement direct. |
83
+ | \`hideVisualizer\`| Boolean | \`false\` | Masque les 3 barres animées à côté du titre. |
84
+ | \`autoOpen\` | Boolean | \`false\` | Déploie le widget automatiquement lors de la première visite. |
85
+ | \`defaultGenre\` | String | \`'all'\` | L'ID du genre au démarrage (ex: \`'10'\` pour House). |
86
+ | \`startVolume\` | Number | \`0.5\` | Volume initial entre 0.0 et 1.0 (surchargé si l'utilisateur a déjà un cache). |
87
+ | \`apiUrl\` | String | *https://www.wordreference.com/definition/interne* | URL de l'API Backend. |
88
+
89
+ ---
90
+
91
+ ## 🎨 Personnalisation CSS Avancée
92
+
93
+ Le widget expose des **Variables CSS** (Custom Properties) rattachées à l'ID `#ncs-persistent-widget`. Vous pouvez les surcharger directement dans la feuille de style de votre site :
94
+
95
+ \`\`\`css
96
+ #ncs-persistent-widget {
97
+ --ncs-bg: #000000; /* Fond du widget */
98
+ --ncs-border: #333333; /* Couleur de la bordure */
99
+ --ncs-panel-bg: #111111; /* Fond des listes et des images */
100
+ }
101
+ \`\`\`
102
+
103
+ ---
104
+
105
+ ## 🏗️ Architecture & Backend
106
+
107
+ En raison des restrictions CORS strictes sur le web moderne, un navigateur web ne peut pas interroger directement le site de NCS. Ce widget s'appuie donc sur une API Backend Node.js qui sert de relais de données (Proxy).
108
+
109
+ ---
110
+
111
+ ## 📄 Licence
112
+
113
+ Distribué sous la licence MIT. Voir `LICENSE` pour plus d'informations.
114
+
115
+ **Avertissement :** Ce projet n'est pas affilié à NoCopyrightSounds. Toutes les musiques diffusées par ce widget appartiennent à leurs créateurs respectifs et à NCS. Veuillez respecter les conditions d'utilisation de NoCopyrightSounds lors de l'utilisation de leurs œuvres.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nocopyrightsounds-widget",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Un widget musical persistant pour site web utilisant l'API NoCopyrightSounds",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -11,7 +11,14 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/floriangobin/nocopyrightsounds-widget.git"
13
13
  },
14
- "keywords": ["ncs", "music", "widget", "audio", "player", "nocopyrightsounds"],
14
+ "keywords": [
15
+ "ncs",
16
+ "music",
17
+ "widget",
18
+ "audio",
19
+ "player",
20
+ "nocopyrightsounds"
21
+ ],
15
22
  "author": "GOBIN Florian",
16
23
  "license": "MIT"
17
- }
24
+ }
package/src/genres.js ADDED
@@ -0,0 +1,71 @@
1
+ // src/genres.js
2
+
3
+ export const ncsGenres = [
4
+ { value: "all", label: "🌍 Tous les genres" },
5
+ { value: "31", label: "Alternative Dance" },
6
+ { value: "32", label: "Alternative Hip-Hop" },
7
+ { value: "33", label: "Alternative Pop" },
8
+ { value: "23", label: "Ambient" },
9
+ { value: "34", label: "Anti-Pop" },
10
+ { value: "1", label: "Bass" },
11
+ { value: "18", label: "Bass House" },
12
+ { value: "78", label: "Bass Music" },
13
+ { value: "26", label: "Brazilian Phonk" },
14
+ { value: "27", label: "Breakbeat" },
15
+ { value: "2", label: "Chill" },
16
+ { value: "24", label: "Chill Bass" },
17
+ { value: "35", label: "Chill Pop" },
18
+ { value: "85", label: "Colour Bass" },
19
+ { value: "65", label: "Complextro" },
20
+ { value: "36", label: "Dance-Pop" },
21
+ { value: "66", label: "Deep House" },
22
+ { value: "45", label: "Disco" },
23
+ { value: "46", label: "Disco House" },
24
+ { value: "3", label: "Drum & Bass" },
25
+ { value: "4", label: "Drumstep" },
26
+ { value: "5", label: "Dubstep" },
27
+ { value: "6", label: "EDM" },
28
+ { value: "47", label: "Electro" },
29
+ { value: "48", label: "Electro House" },
30
+ { value: "7", label: "Electronic" },
31
+ { value: "39", label: "Electronic Pop" },
32
+ { value: "83", label: "Electronic Rock" },
33
+ { value: "17", label: "Future Bass" },
34
+ { value: "68", label: 'Future Bounce' },
35
+ { value: "50", label: "Future Funk" },
36
+ { value: "8", label: "Future House" },
37
+ { value: "69", label: "Future Rave" },
38
+ { value: "57", label: "Future Trap" },
39
+ { value: "40", label: "Futurepop" },
40
+ { value: "51", label: "Garage" },
41
+ { value: "15", label: "Glitch Hop" },
42
+ { value: "82", label: "Hardcore" },
43
+ { value: "9", label: "Hardstyle" },
44
+ { value: "10", label: "House" },
45
+ { value: "41", label: "Hyperpop" },
46
+ { value: "11", label: "Indie Dance" },
47
+ { value: "91", label: "J-Pop" },
48
+ { value: "84", label: "Jersey Club" },
49
+ { value: "28", label: "Jump-Up" },
50
+ { value: "29", label: "Liquid DnB" },
51
+ { value: "60", label: "Lofi Hip-Hop" },
52
+ { value: "12", label: "Melodic Dubstep" },
53
+ { value: "54", label: "Melodic House" },
54
+ { value: "22", label: "Midtempo Bass" },
55
+ { value: "30", label: "Neurofunk" },
56
+ { value: "87", label: "Nu-Jazz" },
57
+ { value: "16", label: "Phonk" },
58
+ { value: "86", label: "Pluggnb" },
59
+ { value: "19", label: "Pop" },
60
+ { value: "55", label: "Progressive House" },
61
+ { value: "88", label: "RnB" },
62
+ { value: "89", label: "Speed Garage" },
63
+ { value: "73", label: "Tech House" },
64
+ { value: "80", label: "Techno" },
65
+ { value: "81", label: "Trance" },
66
+ { value: "14", label: "Trap" },
67
+ { value: "74", label: "Tribal House" },
68
+ { value: "21", label: "UKG" },
69
+ { value: "92", label: "Wave" },
70
+ { value: "90", label: "Witch House" }
71
+ ];
package/src/index.js CHANGED
@@ -1,15 +1,24 @@
1
+ import { ncsGenres } from './genres.js';
2
+
1
3
  class NCSWidget {
2
4
  constructor(userOptions = {}) {
3
- // 🛠️ 1. Configurations par défaut (Fusionnées avec les choix de l'utilisateur)
5
+ // 🛠️ 1. Les TOUTES NOUVELLES options de personnalisation
4
6
  const defaultOptions = {
5
7
  position: 'bottom-right',
6
8
  apiUrl: 'https://VOTRE-URL-RENDER.onrender.com', // ⚠️ METTEZ VOTRE URL RENDER ICI
7
- theme: 'dark', // 'dark' ou 'light'
8
- primaryColor: '#1DB954', // Vert NCS par défaut
9
+ theme: 'dark',
10
+ primaryColor: '#1DB954',
9
11
  defaultGenre: 'all',
10
12
  startVolume: 0.5,
11
- offset: '25px', // Distance par rapport au bord de l'écran
12
- zIndex: 99999
13
+ offset: '25px',
14
+ zIndex: 99999,
15
+ // --- NOUVEAUTÉS V1.2.0 ---
16
+ glassmorphism: false, // Active l'effet verre dépoli
17
+ borderRadius: '16px', // Arrondi des angles du panneau
18
+ fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
19
+ hideDownload: false, // Masquer le bouton de téléchargement
20
+ hideVisualizer: false,// Masquer les barres animées
21
+ autoOpen: false // Ouvrir le widget par défaut à la 1ère visite
13
22
  };
14
23
 
15
24
  this.options = { ...defaultOptions, ...userOptions };
@@ -33,7 +42,14 @@ class NCSWidget {
33
42
  this.savedCover = localStorage.getItem('ncs_currentCover') || null;
34
43
  this.savedTitle = localStorage.getItem('ncs_currentTitle') || null;
35
44
  this.savedArtists = localStorage.getItem('ncs_currentArtists') || null;
36
- this.isWidgetOpen = localStorage.getItem('ncs_isOpen') === 'true';
45
+
46
+ // Logique d'auto-ouverture : on priorise le choix sauvegardé, sinon l'option autoOpen
47
+ const savedState = localStorage.getItem('ncs_isOpen');
48
+ if (savedState !== null) {
49
+ this.isWidgetOpen = savedState === 'true';
50
+ } else {
51
+ this.isWidgetOpen = this.options.autoOpen;
52
+ }
37
53
  }
38
54
 
39
55
  this.initDOM();
@@ -43,7 +59,6 @@ class NCSWidget {
43
59
  this.restoreTrack();
44
60
  this.fillQueue(this.genreSelect.value);
45
61
  } else {
46
- // Utiliser le genre par défaut défini dans les options
47
62
  this.genreSelect.value = this.options.defaultGenre;
48
63
  this.changeGenre(this.options.defaultGenre);
49
64
  }
@@ -55,14 +70,18 @@ class NCSWidget {
55
70
  this.container = document.createElement('div');
56
71
  this.container.id = 'ncs-persistent-widget';
57
72
 
58
- // 🎨 2. Application du thème (Variables CSS dynamiques)
59
73
  const isLight = this.options.theme === 'light';
74
+
75
+ // 🎨 Gestion dynamique des couleurs pour le Glassmorphism
76
+ const baseBgColor = isLight ? '255, 255, 255' : '24, 24, 24';
77
+ const finalBg = this.options.glassmorphism ? `rgba(${baseBgColor}, 0.75)` : (isLight ? '#ffffff' : '#181818');
78
+ const backdropFilter = this.options.glassmorphism ? 'blur(12px)' : 'none';
79
+
60
80
  const colors = {
61
- bg: isLight ? '#ffffff' : '#181818',
62
81
  text: isLight ? '#222222' : '#ffffff',
63
82
  textMuted: isLight ? '#666666' : '#b3b3b3',
64
- border: isLight ? '#e0e0e0' : '#282828',
65
- panelBg: isLight ? '#f5f5f5' : '#282828',
83
+ border: this.options.glassmorphism ? `rgba(${isLight ? '0,0,0' : '255,255,255'}, 0.1)` : (isLight ? '#e0e0e0' : '#282828'),
84
+ panelBg: this.options.glassmorphism ? `rgba(${isLight ? '0,0,0' : '255,255,255'}, 0.05)` : (isLight ? '#f5f5f5' : '#282828'),
66
85
  sliderBg: isLight ? '#d3d3d3' : '#535353',
67
86
  btnBg: isLight ? '#222222' : '#ffffff',
68
87
  btnColor: isLight ? '#ffffff' : '#000000'
@@ -71,9 +90,8 @@ class NCSWidget {
71
90
  const style = document.createElement('style');
72
91
  style.textContent = `
73
92
  #ncs-persistent-widget {
74
- /* Variables CSS exposées pour les développeurs */
75
93
  --ncs-primary: ${this.options.primaryColor};
76
- --ncs-bg: ${colors.bg};
94
+ --ncs-bg: ${finalBg};
77
95
  --ncs-text: ${colors.text};
78
96
  --ncs-text-muted: ${colors.textMuted};
79
97
  --ncs-border: ${colors.border};
@@ -81,11 +99,13 @@ class NCSWidget {
81
99
  --ncs-slider-bg: ${colors.sliderBg};
82
100
  --ncs-btn-bg: ${colors.btnBg};
83
101
  --ncs-btn-color: ${colors.btnColor};
102
+ --ncs-radius: ${this.options.borderRadius};
103
+ --ncs-font: ${this.options.fontFamily};
84
104
 
85
105
  position: fixed;
86
106
  ${this.getPositionStyles()}
87
107
  z-index: ${this.options.zIndex};
88
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
108
+ font-family: var(--ncs-font);
89
109
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
90
110
  }
91
111
 
@@ -93,7 +113,7 @@ class NCSWidget {
93
113
  .ncs-minimized:hover { transform: scale(1.1); }
94
114
  .ncs-minimized.hidden { display: none; }
95
115
 
96
- .ncs-expanded { width: 320px; background: var(--ncs-bg); color: var(--ncs-text); border-radius: 16px; padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: none; border: 1px solid var(--ncs-border); }
116
+ .ncs-expanded { width: 320px; background: var(--ncs-bg); color: var(--ncs-text); border-radius: var(--ncs-radius); padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: none; border: 1px solid var(--ncs-border); backdrop-filter: ${backdropFilter}; -webkit-backdrop-filter: ${backdropFilter}; }
97
117
  .ncs-expanded.active { display: block; animation: ncsFadeIn 0.3s ease; }
98
118
 
99
119
  .ncs-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
@@ -101,7 +121,8 @@ class NCSWidget {
101
121
  .ncs-close-btn { background: transparent; border: none; color: var(--ncs-text-muted); font-size: 18px; cursor: pointer; padding: 0; transition: color 0.2s; }
102
122
  .ncs-close-btn:hover { color: var(--ncs-text); }
103
123
 
104
- .ncs-visualizer { display: flex; gap: 2px; height: 12px; align-items: flex-end; opacity: 0; transition: opacity 0.3s; }
124
+ /* Masquage conditionnel du Visualizer */
125
+ .ncs-visualizer { display: ${this.options.hideVisualizer ? 'none' : 'flex'}; gap: 2px; height: 12px; align-items: flex-end; opacity: 0; transition: opacity 0.3s; }
105
126
  .ncs-visualizer.playing { opacity: 1; }
106
127
  .ncs-bar { width: 3px; background: var(--ncs-primary); border-radius: 2px; animation: bounce 0.5s infinite alternate; }
107
128
  .ncs-bar:nth-child(2) { animation-delay: 0.15s; }
@@ -109,7 +130,7 @@ class NCSWidget {
109
130
  @keyframes bounce { from { height: 3px; } to { height: 12px; } }
110
131
 
111
132
  .ncs-track-info { display: flex; align-items: center; margin-bottom: 15px; }
112
- .ncs-cover { width: 65px; height: 65px; border-radius: 8px; background: var(--ncs-panel-bg); margin-right: 15px; object-fit: cover; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
133
+ .ncs-cover { width: 65px; height: 65px; border-radius: calc(var(--ncs-radius) / 2); background: var(--ncs-panel-bg); margin-right: 15px; object-fit: cover; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
113
134
  .ncs-details { flex: 1; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
114
135
  #ncs-track-name { font-size: 14px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px; }
115
136
  #ncs-artists { font-size: 11px; color: var(--ncs-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 8px; }
@@ -132,12 +153,18 @@ class NCSWidget {
132
153
  .ncs-volume-container { display: flex; align-items: center; gap: 8px; color: var(--ncs-text-muted); flex: 1; margin-right: 15px; }
133
154
  #ncs-mute-btn { cursor: pointer; transition: transform 0.1s; user-select: none; }
134
155
  #ncs-mute-btn:hover { transform: scale(1.1); }
135
- .ncs-download-btn { color: var(--ncs-text-muted); text-decoration: none; font-size: 18px; transition: color 0.2s; }
156
+
157
+ /* Masquage conditionnel du bouton Téléchargement */
158
+ .ncs-download-btn { display: ${this.options.hideDownload ? 'none' : 'block'}; color: var(--ncs-text-muted); text-decoration: none; font-size: 18px; transition: color 0.2s; }
136
159
  .ncs-download-btn:hover { color: var(--ncs-primary); }
137
160
 
138
161
  @keyframes ncsFadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
139
162
  `;
140
163
 
164
+ const genresOptionsHTML = ncsGenres.map(genre =>
165
+ `<option value="${genre.value}">${genre.label}</option>`
166
+ ).join('');
167
+
141
168
  this.container.innerHTML = `
142
169
  <div class="ncs-minimized ${this.isWidgetOpen ? 'hidden' : ''}">🎧</div>
143
170
  <div class="ncs-expanded ${this.isWidgetOpen ? 'active' : ''}">
@@ -156,16 +183,8 @@ class NCSWidget {
156
183
  <div id="ncs-track-name">Chargement...</div>
157
184
  <div id="ncs-artists">Artiste(s)</div>
158
185
  <select id="ncs-genre">
159
- <option value="all">🌍 Tous les genres</option>
160
- <option value="31">Alternative Dance</option>
161
- <option value="10">House</option>
162
- <option value="2">Chill</option>
163
- <option value="5">Dubstep</option>
164
- <option value="7">Electronic</option>
165
- <option value="3">Drum & Bass</option>
166
- <option value="9">Hardstyle</option>
167
- <option value="14">Trap</option>
168
- </select>
186
+ ${genresOptionsHTML}
187
+ </select>
169
188
  </div>
170
189
  </div>
171
190
 
@@ -194,7 +213,6 @@ class NCSWidget {
194
213
  document.head.appendChild(style);
195
214
  document.body.appendChild(this.container);
196
215
 
197
- // Références
198
216
  this.minimized = this.container.querySelector('.ncs-minimized');
199
217
  this.expanded = this.container.querySelector('.ncs-expanded');
200
218
  this.playBtn = this.container.querySelector('#ncs-play-pause');