useSoundcloudPlayer.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { ref, watch } from "vue";
  2. export const useSoundcloudPlayer = () => {
  3. const soundcloudIframeElement = ref();
  4. const widgetId = ref();
  5. const volume = ref();
  6. const readyCallback = ref();
  7. const attemptsToPlay = ref(0);
  8. const paused = ref(true);
  9. const methodCallbacks = {};
  10. const eventListenerCallbacks = {};
  11. const dispatchMessage = (method, value = null) => {
  12. const payload = {
  13. method,
  14. value
  15. };
  16. if (!soundcloudIframeElement.value) return;
  17. soundcloudIframeElement.value.contentWindow.postMessage(
  18. JSON.stringify(payload),
  19. "https://w.soundcloud.com/player"
  20. );
  21. };
  22. const onLoadListener = () => {};
  23. const onMessageListener = event => {
  24. if (event.origin !== "https://w.soundcloud.com") return;
  25. const data = JSON.parse(event.data);
  26. if (data.method !== "getPosition") console.log("MESSAGE DATA", data);
  27. if (data.method === "ready") {
  28. widgetId.value = data.widgetId;
  29. if (!readyCallback.value) return;
  30. readyCallback.value();
  31. return;
  32. }
  33. if (methodCallbacks[data.method]) {
  34. methodCallbacks[data.method].forEach(callback => {
  35. callback(data.value);
  36. });
  37. methodCallbacks[data.method] = [];
  38. }
  39. if (eventListenerCallbacks[data.method]) {
  40. eventListenerCallbacks[data.method].forEach(callback => {
  41. callback(data.value);
  42. });
  43. }
  44. };
  45. const addMethodCallback = (type, cb) => {
  46. if (!methodCallbacks[type]) methodCallbacks[type] = [];
  47. methodCallbacks[type].push(cb);
  48. };
  49. const attemptToPlay = () => {
  50. attemptsToPlay.value += 1;
  51. dispatchMessage("play");
  52. dispatchMessage("isPaused", value => {
  53. if (!value || paused.value || attemptsToPlay.value >= 10) return;
  54. setTimeout(() => {
  55. attemptToPlay();
  56. }, 500);
  57. });
  58. };
  59. watch(soundcloudIframeElement, (newElement, oldElement) => {
  60. if (oldElement) {
  61. oldElement.removeEventListener("load", onLoadListener);
  62. window.removeEventListener("message", onMessageListener);
  63. }
  64. if (newElement) {
  65. newElement.addEventListener("load", onLoadListener);
  66. window.addEventListener("message", onMessageListener);
  67. }
  68. });
  69. /* Exported functions */
  70. const soundcloudPlay = () => {
  71. paused.value = false;
  72. console.log("SC PLAY");
  73. dispatchMessage("play");
  74. };
  75. const soundcloudPause = () => {
  76. paused.value = true;
  77. console.log("SC PAUSE");
  78. dispatchMessage("pause");
  79. };
  80. const soundcloudSetVolume = _volume => {
  81. volume.value = _volume;
  82. dispatchMessage("setVolume", _volume);
  83. };
  84. const soundcloudSeekTo = time => {
  85. console.log("SC SEEK TO", time);
  86. dispatchMessage("seekTo", time);
  87. };
  88. const soundcloudGetPosition = callback => {
  89. let called = false;
  90. const _callback = value => {
  91. if (called) return;
  92. called = true;
  93. callback(value);
  94. };
  95. addMethodCallback("getPosition", _callback);
  96. dispatchMessage("getPosition");
  97. };
  98. const soundcloudGetIsPaused = callback => {
  99. let called = false;
  100. const _callback = value => {
  101. if (called) return;
  102. called = true;
  103. callback(value);
  104. };
  105. addMethodCallback("isPaused", _callback);
  106. dispatchMessage("isPaused");
  107. };
  108. const soundcloudLoadTrack = (trackId, startTime, _paused) => {
  109. if (!soundcloudIframeElement.value) return;
  110. const url = `https://w.soundcloud.com/player?autoplay=false&buying=false&sharing=false&download=false&show_artwork=false&show_playcount=false&show_user=false&url=${`https://api.soundcloud.com/tracks/${trackId}`}`;
  111. soundcloudIframeElement.value.setAttribute("src", url);
  112. paused.value = _paused;
  113. readyCallback.value = () => {
  114. Object.keys(eventListenerCallbacks).forEach(event => {
  115. dispatchMessage("addEventListener", event);
  116. });
  117. dispatchMessage("setVolume", volume.value ?? 20);
  118. dispatchMessage("seekTo", (startTime ?? 0) * 1000);
  119. if (!_paused) attemptToPlay();
  120. };
  121. };
  122. const soundcloudBindListener = (name, callback) => {
  123. if (!eventListenerCallbacks[name]) {
  124. eventListenerCallbacks[name] = [];
  125. dispatchMessage("addEventListener", name);
  126. }
  127. eventListenerCallbacks[name].push(callback);
  128. };
  129. const soundcloudDestroy = () => {
  130. if (!soundcloudIframeElement.value) return;
  131. const url = `https://w.soundcloud.com/player?autoplay=false&buying=false&sharing=false&download=false&show_artwork=false&show_playcount=false&show_user=false&url=${`https://api.soundcloud.com/tracks/${0}`}`;
  132. soundcloudIframeElement.value.setAttribute("src", url);
  133. };
  134. const soundcloudUnload = () => {
  135. window.removeEventListener("message", onMessageListener);
  136. };
  137. return {
  138. soundcloudIframeElement,
  139. soundcloudPlay,
  140. soundcloudPause,
  141. soundcloudSeekTo,
  142. soundcloudSetVolume,
  143. soundcloudLoadTrack,
  144. soundcloudGetPosition,
  145. soundcloudGetIsPaused,
  146. soundcloudBindListener,
  147. soundcloudDestroy,
  148. soundcloudUnload
  149. };
  150. };