Tuna browser script

Get song information from web players, based on NowSniper by Kıraç Armağan Önal

当前为 2020-10-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Tuna browser script
  3. // @namespace univrsal
  4. // @version 1.0.1
  5. // @description Get song information from web players, based on NowSniper by Kıraç Armağan Önal
  6. // @author univrsal
  7. // @match *://open.spotify.com/*
  8. // @match *://soundcloud.com/*
  9. // @grant unsafeWindow
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // Configuration
  15. var port = 1608;
  16. var refresh_rate_ms = 500;
  17. var cooldown_ms = 10000;
  18.  
  19. // Tuna isn't running we sleep, because every failed request will log into the console
  20. // so we don't want to spam it
  21. var failure_count = 0;
  22. var cooldown = 0;
  23.  
  24. function post(data){
  25. var url = 'http://localhost:' + port + '/';
  26. var xhr = new XMLHttpRequest();
  27. xhr.open('POST', url);
  28.  
  29. xhr.setRequestHeader('Accept', 'application/json');
  30. xhr.setRequestHeader('Content-Type', 'application/json');
  31. xhr.setRequestHeader('Access-Control-Allow-Headers', '*');
  32. xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
  33.  
  34. xhr.onreadystatechange = function () {
  35. if (xhr.readyState === 4) {
  36. if (xhr.status !== 200) {
  37. failure_count++;
  38. }
  39. }
  40. };
  41. xhr.send(JSON.stringify({data,hostname:window.location.hostname,date:Date.now()}));
  42. }
  43.  
  44. // Safely query something, and perform operations on it
  45. function query(target, fun, alt = null) {
  46. var element = document.querySelector(target);
  47. if (element !== null) {
  48. return fun(element);
  49. }
  50. return alt;
  51. }
  52.  
  53. function timestamp_to_ms(ts) {
  54. var splits = ts.split(':');
  55. if (splits.length == 2) {
  56. return splits[0] * 60 * 1000 + splits[1] * 1000;
  57. } else if (splits.length == 3) {
  58. return splits[0] * 60 * 60 * 1000 + splits[1] * 60 * 1000 + splits[0] * 1000;
  59. }
  60. return 0;
  61. }
  62.  
  63. function StartFunction() {
  64. setInterval(()=>{
  65. if (failure_count > 3) {
  66. console.log('Failed to connect multiple times, waiting a few seconds');
  67. cooldown = cooldown_ms;
  68. failure_count = 0;
  69. }
  70.  
  71. if (cooldown > 0) {
  72. cooldown -= refresh_rate_ms;
  73. return;
  74. }
  75.  
  76. let hostname = window.location.hostname;
  77.  
  78. // TODO: maybe add more?
  79. if (hostname == 'soundcloud.com') {
  80. let status = query('.playControl', e => e.classList.contains('playing') ? "playing" : "stopped", 'unknown');
  81. let cover_url = query('.playbackSoundBadge span.sc-artwork', e => e.style.backgroundImage.slice(5, -2).replace('t50x50','t500x500'));
  82. let title = query('.playbackSoundBadge__titleLink', e => e.title);
  83. let artists = [ query('.playbackSoundBadge__lightLink', e => e.title) ];
  84. let progress = query('.playbackTimeline__timePassed span:nth-child(2)', e => timestamp_to_ms(e.textContent));
  85. let duration = query('.playbackTimeline__duration span:nth-child(2)', e => timestamp_to_ms(e.textContent));
  86. let album_url = query('.playbackSoundBadge__titleLink', e => e.href);
  87.  
  88. if (title !== null) {
  89. post({ cover_url, title, artists, status, progress, duration, album_url });
  90. }
  91. } else if (hostname == 'open.spotify.com') {
  92. let status = query('.player-controls [data-testid="control-button-pause"]', e => !!e ? 'playing' : 'stopped', 'unknown');
  93. let cover_url = query('[data-testid="CoverSlotExpanded__container"] .cover-art-image', e => e.style.backgroundImage.slice(5, -2));
  94. let title = query('[data-testid="nowplaying-track-link"]', e => e.textContent);
  95. let artists = query('span[draggable] a[href*="artist"]', e => Array.from(e));
  96. let progress = query('.playback-bar .playback-bar__progress-time', e => timestamp_to_ms(e[0].textContent));
  97. let duration = query('.playback-bar .playback-bar__progress-time', e => timestamp_to_ms(e[1].textContent));
  98. let album_url = query('[data-testid="nowplaying-track-link"]', e => e.href);
  99.  
  100. if (title !== null) {
  101. post({ cover_url, title, artists, status, progress, duration, album_url });
  102. }
  103. }
  104.  
  105. }, 500);
  106.  
  107. }
  108.  
  109. StartFunction();
  110. })();