last.fm 1-click delete

Shows a delete "x" button for scrobbles

  1. // ==UserScript==
  2. // @name last.fm 1-click delete
  3. // @description Shows a delete "x" button for scrobbles
  4. // @version 1.0.4
  5. // @author wOxxOm
  6. // @namespace wOxxOm.scripts
  7. // @license MIT License
  8. // @match https://www.last.fm/*
  9. // @grant GM_addStyle
  10. // @run-at document-end
  11. // ==/UserScript==
  12.  
  13. GM_addStyle(`
  14. .one-click-delete {
  15. position: absolute;
  16. margin-left: .25em;
  17. opacity: .5;
  18. cursor: pointer;
  19. padding: 0px 8px;
  20. }
  21. .one-click-delete:hover {
  22. background-color: rgba(255,0,0,0.1);
  23. opacity: 1.0;
  24. color: red;
  25. font-weight: bold;
  26. }
  27. `);
  28.  
  29. const ROW_SELECTOR = '.chartlist-row:not(.has-one-click-delete):not(.chartlist-row--now-scrobbling)';
  30. const observer = new MutationObserver(() => $(ROW_SELECTOR) && process());
  31.  
  32. process();
  33. registerPJAXforwarding();
  34.  
  35. function process() {
  36. observer.disconnect();
  37. $$(ROW_SELECTOR + ' .chartlist-timestamp').forEach(el => {
  38. el.appendChild(Object.assign(
  39. document.createElement('span'), {
  40. className: 'one-click-delete',
  41. textContent: 'X',
  42. title: 'Delete',
  43. onclick: onClick,
  44. }
  45. ));
  46. });
  47. if ($('.chartlist tbody')) {
  48. observer.takeRecords();
  49. observer.observe($('.chartlist tbody'), {childList: true});
  50. }
  51. }
  52.  
  53. function registerPJAXforwarding() {
  54. document.addEventListener('pjax:end:1-click-delete', process);
  55. window.addEventListener('load', function _() {
  56. window.removeEventListener('load', _);
  57. unsafeWindow.jQuery(unsafeWindow.document).on('pjax:end',
  58. () => document.dispatchEvent(new CustomEvent('pjax:end:1-click-delete')));
  59. });
  60. }
  61.  
  62. function onClick() {
  63. const delButton = this.closest('tr').querySelector('[data-ajax-form-sets-state="deleted"]');
  64. delButton && delButton.click();
  65. }
  66.  
  67. function $(selector, base) {
  68. return (base || document).querySelector(selector);
  69. }
  70.  
  71. function $$(selector, base) {
  72. return Array.prototype.slice.call((base || document).querySelectorAll(selector));
  73. }