tunzo-player 1.0.27 → 1.0.29

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.
@@ -13,6 +13,8 @@ export declare class Player {
13
13
  private static selectedQuality;
14
14
  /** Initialize with playlist and quality */
15
15
  static initialize(playlist: any[], quality?: number): void;
16
+ /** Setup audio element for better compatibility */
17
+ private static setupAudioElement;
16
18
  /** Call this once on user gesture to unlock audio in WebView */
17
19
  static unlockAudio(): void;
18
20
  static play(song: any, index?: number): void;
@@ -37,8 +39,6 @@ export declare class Player {
37
39
  static setQuality(index: number): void;
38
40
  static getQueue(): any[];
39
41
  static getPlaylist(): any[];
40
- private static enableBackgroundMode;
41
- private static disableBackgroundMode;
42
42
  private static setupMediaSession;
43
43
  private static updateMediaSessionMetadata;
44
44
  private static updatePositionState;
@@ -1,17 +1,7 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Player = void 0;
13
4
  const rxjs_1 = require("rxjs");
14
- const capacitor_background_mode_1 = require("@anuradev/capacitor-background-mode");
15
5
  const keep_awake_1 = require("@capacitor-community/keep-awake");
16
6
  class Player {
17
7
  /** Initialize with playlist and quality */
@@ -19,6 +9,48 @@ class Player {
19
9
  this.playlist = playlist;
20
10
  this.selectedQuality = quality;
21
11
  this.setupMediaSession();
12
+ this.setupAudioElement();
13
+ }
14
+ /** Setup audio element for better compatibility */
15
+ static setupAudioElement() {
16
+ // Enable background playback
17
+ this.audio.preload = 'auto';
18
+ // @ts-ignore - Some browsers support this
19
+ this.audio.preservesPitch = false;
20
+ // Setup event listeners
21
+ this.audio.onloadedmetadata = () => {
22
+ this.duration = this.audio.duration;
23
+ this.updatePositionState();
24
+ };
25
+ this.audio.ontimeupdate = () => {
26
+ this.currentTime = this.audio.currentTime;
27
+ if (Math.floor(this.currentTime) % 5 === 0) {
28
+ this.updatePositionState();
29
+ }
30
+ };
31
+ this.audio.onended = () => {
32
+ this.autoNext();
33
+ };
34
+ this.audio.onplaying = () => {
35
+ this.isPlaying = true;
36
+ if ('mediaSession' in navigator) {
37
+ navigator.mediaSession.playbackState = 'playing';
38
+ }
39
+ };
40
+ this.audio.onpause = () => {
41
+ this.isPlaying = false;
42
+ if ('mediaSession' in navigator) {
43
+ navigator.mediaSession.playbackState = 'paused';
44
+ }
45
+ };
46
+ this.audio.onwaiting = () => {
47
+ if ('mediaSession' in navigator) {
48
+ navigator.mediaSession.playbackState = 'none';
49
+ }
50
+ };
51
+ this.audio.onerror = (e) => {
52
+ console.error('Audio error:', this.audio.error, e);
53
+ };
22
54
  }
23
55
  /** Call this once on user gesture to unlock audio in WebView */
24
56
  static unlockAudio() {
@@ -26,7 +58,6 @@ class Player {
26
58
  this.audio.load();
27
59
  this.audio.play().catch(() => { });
28
60
  }
29
- //updated
30
61
  static play(song, index = 0) {
31
62
  var _a;
32
63
  if (!song || !song.downloadUrl)
@@ -39,14 +70,11 @@ class Player {
39
70
  url = url.replace('http://', 'https://');
40
71
  }
41
72
  this.audio.src = url;
42
- // @ts-ignore
43
- this.audio.title = song.name || song.title || 'Unknown Title'; // Help some browsers identify the track
44
- this.audio.preload = 'auto'; // Improve loading
45
- this.audio.load(); // Ensure audio is loaded before play
73
+ this.audio.load();
46
74
  this.audio.play().then(() => {
47
75
  this.isPlaying = true;
48
76
  this.updateMediaSessionMetadata(song);
49
- this.enableBackgroundMode();
77
+ keep_awake_1.KeepAwake.keepAwake(); // Keep screen/CPU awake
50
78
  if ('mediaSession' in navigator) {
51
79
  navigator.mediaSession.playbackState = 'playing';
52
80
  }
@@ -54,44 +82,11 @@ class Player {
54
82
  this.isPlaying = false;
55
83
  console.warn('Audio play failed:', err);
56
84
  });
57
- // Set duration
58
- this.audio.onloadedmetadata = () => {
59
- this.duration = this.audio.duration;
60
- this.updatePositionState();
61
- };
62
- // Set current time
63
- this.audio.ontimeupdate = () => {
64
- this.currentTime = this.audio.currentTime;
65
- // Update position state less frequently to avoid spamming, but enough to keep sync
66
- if (Math.floor(this.currentTime) % 5 === 0) {
67
- this.updatePositionState();
68
- }
69
- };
70
- // Handle buffering/stalled states
71
- this.audio.onwaiting = () => {
72
- if ('mediaSession' in navigator) {
73
- navigator.mediaSession.playbackState = 'none'; // Or 'paused' to indicate buffering
74
- }
75
- };
76
- this.audio.onplaying = () => {
77
- this.isPlaying = true;
78
- if ('mediaSession' in navigator) {
79
- navigator.mediaSession.playbackState = 'playing';
80
- }
81
- };
82
- // Auto-play next song
83
- this.audio.onended = () => {
84
- this.autoNext();
85
- };
86
- // Catch errors
87
- this.audio.onerror = (e) => {
88
- console.error('Audio error:', this.audio.error, e);
89
- };
90
85
  }
91
86
  static pause() {
92
87
  this.audio.pause();
93
88
  this.isPlaying = false;
94
- this.disableBackgroundMode();
89
+ keep_awake_1.KeepAwake.allowSleep();
95
90
  if ('mediaSession' in navigator) {
96
91
  navigator.mediaSession.playbackState = 'paused';
97
92
  }
@@ -99,6 +94,7 @@ class Player {
99
94
  static resume() {
100
95
  this.audio.play();
101
96
  this.isPlaying = true;
97
+ keep_awake_1.KeepAwake.keepAwake();
102
98
  if ('mediaSession' in navigator) {
103
99
  navigator.mediaSession.playbackState = 'playing';
104
100
  }
@@ -194,43 +190,6 @@ class Player {
194
190
  return this.playlist;
195
191
  }
196
192
  // -------------------------------------------------------------------------
197
- // Capacitor Background Mode & Keep Awake
198
- // -------------------------------------------------------------------------
199
- static enableBackgroundMode() {
200
- return __awaiter(this, void 0, void 0, function* () {
201
- try {
202
- yield keep_awake_1.KeepAwake.keepAwake();
203
- yield capacitor_background_mode_1.BackgroundMode.enable({
204
- title: "Tunzo Player",
205
- text: "Playing music in background",
206
- icon: "ic_launcher",
207
- color: "042730",
208
- resume: true,
209
- hidden: false,
210
- bigText: true,
211
- disableWebViewOptimization: true
212
- });
213
- }
214
- catch (err) {
215
- // Plugin might not be installed or on web
216
- }
217
- });
218
- }
219
- static disableBackgroundMode() {
220
- return __awaiter(this, void 0, void 0, function* () {
221
- try {
222
- yield keep_awake_1.KeepAwake.allowSleep();
223
- // We might want to keep background mode enabled if we want to resume later,
224
- // but for battery saving, we can disable it or move to background.
225
- // await BackgroundMode.disable();
226
- yield capacitor_background_mode_1.BackgroundMode.moveToBackground();
227
- }
228
- catch (err) {
229
- // Plugin might not be installed or on web
230
- }
231
- });
232
- }
233
- // -------------------------------------------------------------------------
234
193
  // Native Media Session (Lock Screen Controls)
235
194
  // -------------------------------------------------------------------------
236
195
  static setupMediaSession() {
@@ -252,11 +211,9 @@ class Player {
252
211
  const artwork = [];
253
212
  if (song.image) {
254
213
  if (Array.isArray(song.image)) {
255
- // Assuming image array contains objects with url/link and quality
256
214
  song.image.forEach((img) => {
257
215
  let src = img.link || img.url || (typeof img === 'string' ? img : '');
258
216
  if (src) {
259
- // 🚀 Auto-convert http → https for images too
260
217
  if (src.startsWith('http://')) {
261
218
  src = src.replace('http://', 'https://');
262
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tunzo-player",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "description": "A music playback service for Angular and Ionic apps with native audio control support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,7 +29,6 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@anuradev/capacitor-background-mode": "^7.2.1",
33
32
  "@capacitor-community/keep-awake": "^7.1.0",
34
33
  "rxjs": "^7.8.2"
35
34
  }
@@ -1,5 +1,4 @@
1
1
  import { BehaviorSubject } from 'rxjs';
2
- import { BackgroundMode } from '@anuradev/capacitor-background-mode';
3
2
  import { KeepAwake } from '@capacitor-community/keep-awake';
4
3
 
5
4
  export class Player {
@@ -20,6 +19,56 @@ export class Player {
20
19
  this.playlist = playlist;
21
20
  this.selectedQuality = quality;
22
21
  this.setupMediaSession();
22
+ this.setupAudioElement();
23
+ }
24
+
25
+ /** Setup audio element for better compatibility */
26
+ private static setupAudioElement() {
27
+ // Enable background playback
28
+ this.audio.preload = 'auto';
29
+ // @ts-ignore - Some browsers support this
30
+ this.audio.preservesPitch = false;
31
+
32
+ // Setup event listeners
33
+ this.audio.onloadedmetadata = () => {
34
+ this.duration = this.audio.duration;
35
+ this.updatePositionState();
36
+ };
37
+
38
+ this.audio.ontimeupdate = () => {
39
+ this.currentTime = this.audio.currentTime;
40
+ if (Math.floor(this.currentTime) % 5 === 0) {
41
+ this.updatePositionState();
42
+ }
43
+ };
44
+
45
+ this.audio.onended = () => {
46
+ this.autoNext();
47
+ };
48
+
49
+ this.audio.onplaying = () => {
50
+ this.isPlaying = true;
51
+ if ('mediaSession' in navigator) {
52
+ navigator.mediaSession.playbackState = 'playing';
53
+ }
54
+ };
55
+
56
+ this.audio.onpause = () => {
57
+ this.isPlaying = false;
58
+ if ('mediaSession' in navigator) {
59
+ navigator.mediaSession.playbackState = 'paused';
60
+ }
61
+ };
62
+
63
+ this.audio.onwaiting = () => {
64
+ if ('mediaSession' in navigator) {
65
+ navigator.mediaSession.playbackState = 'none';
66
+ }
67
+ };
68
+
69
+ this.audio.onerror = (e) => {
70
+ console.error('Audio error:', this.audio.error, e);
71
+ };
23
72
  }
24
73
 
25
74
  /** Call this once on user gesture to unlock audio in WebView */
@@ -28,7 +77,6 @@ export class Player {
28
77
  this.audio.load();
29
78
  this.audio.play().catch(() => { });
30
79
  }
31
- //updated
32
80
 
33
81
  static play(song: any, index: number = 0) {
34
82
  if (!song || !song.downloadUrl) return;
@@ -44,14 +92,12 @@ export class Player {
44
92
  }
45
93
 
46
94
  this.audio.src = url;
47
- // @ts-ignore
48
- this.audio.title = song.name || song.title || 'Unknown Title'; // Help some browsers identify the track
49
- this.audio.preload = 'auto'; // Improve loading
50
- this.audio.load(); // Ensure audio is loaded before play
95
+ this.audio.load();
96
+
51
97
  this.audio.play().then(() => {
52
98
  this.isPlaying = true;
53
99
  this.updateMediaSessionMetadata(song);
54
- this.enableBackgroundMode();
100
+ KeepAwake.keepAwake(); // Keep screen/CPU awake
55
101
  if ('mediaSession' in navigator) {
56
102
  navigator.mediaSession.playbackState = 'playing';
57
103
  }
@@ -59,52 +105,12 @@ export class Player {
59
105
  this.isPlaying = false;
60
106
  console.warn('Audio play failed:', err);
61
107
  });
62
-
63
- // Set duration
64
- this.audio.onloadedmetadata = () => {
65
- this.duration = this.audio.duration;
66
- this.updatePositionState();
67
- };
68
-
69
- // Set current time
70
- this.audio.ontimeupdate = () => {
71
- this.currentTime = this.audio.currentTime;
72
- // Update position state less frequently to avoid spamming, but enough to keep sync
73
- if (Math.floor(this.currentTime) % 5 === 0) {
74
- this.updatePositionState();
75
- }
76
- };
77
-
78
- // Handle buffering/stalled states
79
- this.audio.onwaiting = () => {
80
- if ('mediaSession' in navigator) {
81
- navigator.mediaSession.playbackState = 'none'; // Or 'paused' to indicate buffering
82
- }
83
- };
84
-
85
- this.audio.onplaying = () => {
86
- this.isPlaying = true;
87
- if ('mediaSession' in navigator) {
88
- navigator.mediaSession.playbackState = 'playing';
89
- }
90
- };
91
-
92
- // Auto-play next song
93
- this.audio.onended = () => {
94
- this.autoNext();
95
- };
96
-
97
- // Catch errors
98
- this.audio.onerror = (e) => {
99
- console.error('Audio error:', this.audio.error, e);
100
- };
101
108
  }
102
109
 
103
-
104
110
  static pause() {
105
111
  this.audio.pause();
106
112
  this.isPlaying = false;
107
- this.disableBackgroundMode();
113
+ KeepAwake.allowSleep();
108
114
  if ('mediaSession' in navigator) {
109
115
  navigator.mediaSession.playbackState = 'paused';
110
116
  }
@@ -113,6 +119,7 @@ export class Player {
113
119
  static resume() {
114
120
  this.audio.play();
115
121
  this.isPlaying = true;
122
+ KeepAwake.keepAwake();
116
123
  if ('mediaSession' in navigator) {
117
124
  navigator.mediaSession.playbackState = 'playing';
118
125
  }
@@ -156,12 +163,10 @@ export class Player {
156
163
 
157
164
  static playRandom() {
158
165
  if (this.playlist.length <= 1) return;
159
-
160
166
  let randomIndex;
161
167
  do {
162
168
  randomIndex = Math.floor(Math.random() * this.playlist.length);
163
169
  } while (randomIndex === this.currentIndex);
164
-
165
170
  this.play(this.playlist[randomIndex], randomIndex);
166
171
  }
167
172
 
@@ -225,40 +230,6 @@ export class Player {
225
230
  return this.playlist;
226
231
  }
227
232
 
228
- // -------------------------------------------------------------------------
229
- // Capacitor Background Mode & Keep Awake
230
- // -------------------------------------------------------------------------
231
-
232
- private static async enableBackgroundMode() {
233
- try {
234
- await KeepAwake.keepAwake();
235
- await BackgroundMode.enable({
236
- title: "Tunzo Player",
237
- text: "Playing music in background",
238
- icon: "ic_launcher",
239
- color: "042730",
240
- resume: true,
241
- hidden: false,
242
- bigText: true,
243
- disableWebViewOptimization: true
244
- });
245
- } catch (err) {
246
- // Plugin might not be installed or on web
247
- }
248
- }
249
-
250
- private static async disableBackgroundMode() {
251
- try {
252
- await KeepAwake.allowSleep();
253
- // We might want to keep background mode enabled if we want to resume later,
254
- // but for battery saving, we can disable it or move to background.
255
- // await BackgroundMode.disable();
256
- await BackgroundMode.moveToBackground();
257
- } catch (err) {
258
- // Plugin might not be installed or on web
259
- }
260
- }
261
-
262
233
  // -------------------------------------------------------------------------
263
234
  // Native Media Session (Lock Screen Controls)
264
235
  // -------------------------------------------------------------------------
@@ -282,11 +253,9 @@ export class Player {
282
253
  const artwork = [];
283
254
  if (song.image) {
284
255
  if (Array.isArray(song.image)) {
285
- // Assuming image array contains objects with url/link and quality
286
256
  song.image.forEach((img: any) => {
287
257
  let src = img.link || img.url || (typeof img === 'string' ? img : '');
288
258
  if (src) {
289
- // 🚀 Auto-convert http → https for images too
290
259
  if (src.startsWith('http://')) {
291
260
  src = src.replace('http://', 'https://');
292
261
  }