Last Picture Show

Link last.fm artist/album images directly to the image page

  1. // ==UserScript==
  2. // @name Last Picture Show
  3. // @description Link last.fm artist/album images directly to the image page
  4. // @author chocolateboy
  5. // @copyright chocolateboy
  6. // @version 1.2.4
  7. // @namespace https://github.com/chocolateboy/userscripts
  8. // @license GPL: https://www.gnu.org/copyleft/gpl.html
  9. // @include http://*.last.fm/*
  10. // @include https://*.last.fm/*
  11. // @include http://*.lastfm.tld/*
  12. // @include https://*.lastfm.tld/*
  13. // @require https://code.jquery.com/jquery-3.5.1.slim.min.js
  14. // @require https://cdn.jsdelivr.net/gh/eclecto/jQuery-onMutate@79bbb2b8caccabfc9b9ade046fe63f15f593fef6/src/jquery.onmutate.min.js
  15. // @grant GM_log
  16. // @inject-into auto
  17. // ==/UserScript==
  18.  
  19. // XXX note: the unused grant is a workaround for a Greasemonkey bug:
  20. // https://github.com/greasemonkey/greasemonkey/issues/1614
  21.  
  22. /*
  23. Thumbnail: https://lastfm-img2.akamaized.net/i/u/300x300/{imageId}.jpg
  24. Picture page: https://www.last.fm/music/Artist+Name/+images/{imageId}
  25.  
  26. before:
  27.  
  28. <div class="grid-items-cover-image js-link-block link-block">
  29. <div class="grid-items-cover-image-image">
  30. <!-- XXX wrap this image in a link -->
  31. <img
  32. src="https://lastfm-img2.akamaized.net/i/u/300x300/1ce40dc1f3ec52cb78efb9f0ae54dddd.jpg"
  33. alt="Image for 'Ellie Goulding'"
  34. />
  35. </div>
  36.  
  37. <div class="grid-items-item-details">
  38. <p class="grid-items-item-main-text">
  39. <!-- XXX grab the path prefix from here -->
  40. <a href="/music/Ellie+Goulding" class="link-block-target">Ellie Goulding</a>
  41. </p>
  42. <p class="grid-items-item-aux-text">
  43. 1,783,906 <span class="stat-name">listeners</span>
  44. </p>
  45. </div>
  46. ...
  47. </div>
  48.  
  49. after:
  50.  
  51. <div class="grid-items-cover-image js-link-block link-block">
  52. <div class="grid-items-cover-image-image">
  53. <a href="/music/Ellie+Goulding/+images/1ce40dc1f3ec52cb78efb9f0ae54dddd">
  54. <img
  55. src="https://lastfm-img2.akamaized.net/i/u/300x300/1ce40dc1f3ec52cb78efb9f0ae54dddd.jpg"
  56. alt="Image for 'Ellie Goulding'"
  57. />
  58. </a>
  59. </div>
  60.  
  61. <div class="grid-items-item-details">
  62. <p class="grid-items-item-main-text">
  63. <a href="/music/Ellie+Goulding" class="link-block-target">Ellie Goulding</a>
  64. </p>
  65. <p class="grid-items-item-aux-text">
  66. 1,783,906 <span class="stat-name">listeners</span>
  67. </p>
  68. </div>
  69. ...
  70. </div>
  71. */
  72.  
  73. // selector for the nearest parent element (div) which contains both the image
  74. // and a link to the artist/album
  75. const ITEM = '.grid-items-cover-image'
  76.  
  77. // filter out "Similar Tracks" tiles (no way to determine the image page) and
  78. // tiles without an image
  79. function filterItems () {
  80. const $item = $(this)
  81.  
  82. // XXX don't include the images in "Similar Tracks" grids. their pages are
  83. // located in album (or release) "subfolders" e.g.:
  84. //
  85. // - image: https://lastfm-img2.akamaized.net/i/u/300x300/fafc74a8f45241acc10158be6e2d8270.jpg
  86. // - track: https://www.last.fm/music/The+Beatles/_/Doctor+Robert
  87. // - image page: https://www.last.fm/music/The+Beatles/Revolver/+images/fafc74a8f45241acc10158be6e2d8270
  88. //
  89. // but last.fm doesn't include any additional data in the "Similar Tracks"
  90. // grids which can be used to identify the release (e.g. "Revolver").
  91. //
  92. // XXX last.fm doesn't distinguish the "Similar Tracks" grid from the "Similar
  93. // Artists" grid in any way (same markup and CSS), so we have to identify
  94. // (and exclude) it as "section 1 of 2 in the similar-tracks-and-artists row"
  95. if ($item.is(`.similar-tracks-and-artists-row section:nth-of-type(1) ${ITEM}`))
  96. return false
  97.  
  98. // XXX we also need to exclude tiles with missing/default images. they have
  99. // an additional .grid-items-cover-default class on their image-container div
  100. // alongside .grid-items-cover-image-image
  101. if ($item.has('.grid-items-cover-default').length)
  102. return false
  103.  
  104. return true
  105. }
  106.  
  107. function onItems ($items) {
  108. $items.filter(filterItems).each(function () {
  109. const $item = $(this)
  110. const $image = $item.find('.grid-items-cover-image-image img[src]')
  111. const imageId = $image.attr('src').match(/\/([^/.]+)\.\w+$/)[1]
  112. const path = $item.find('a.link-block-target[href]').attr('href')
  113.  
  114. $image.wrap(`<a href="${path}/+images/${imageId}"></a>`)
  115. })
  116. }
  117.  
  118. $.onCreate(ITEM, onItems, true /* multi */)

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址