Greasy Fork is available in English.

Supraphon Online: Fetch album info to clipboard

Zkopíruje playlist do schránky tak aby jej bylo možno v hudebním přehrávači aplikovat na tagy

2019-08-03 기준 버전입니다. 최신 버전을 확인하세요.

  1. // ==UserScript==
  2. // @name Supraphon Online: Fetch album info to clipboard
  3. // @namespace https://www.supraphonline.cz/
  4. // @version 1.0
  5. // @description Zkopíruje playlist do schránky tak aby jej bylo možno v hudebním přehrávači aplikovat na tagy
  6. // @author Já, Osobně
  7. // @match https://www.supraphonline.cz/album/*
  8. // @match http://www.supraphonline.cz/album/*
  9. // @run-at document-idle
  10. // @grant RegExp
  11. // @grant GM_getValue
  12. // @grant GM_getValue
  13. // @grant GM_setClipboard
  14. // @grant GM_deleteValue
  15. // @grant GM_xmlhttpRequest
  16. // @grant GM.xmlHttpRequest
  17. // ==/UserScript==
  18.  
  19. // Výraz pro 'Automatically Fill Values" funkci ve foobaru2000:
  20. // %album artist%%album%%date%%releasedate%%genre%%label%%catalog%%discnumber%%totaldiscs%%tracknumber%%totaltracks%%artist%%title%%performer%%composer%%comment%%url%
  21.  
  22. 'use strict';
  23.  
  24. var buttons = document.getElementsByName('buy');
  25. if (buttons == null) return;
  26. var child = document.createElement('button');
  27. child.id = 'copy-info-to-clipboard';
  28. child.textContent = 'Kopírovat do schránky';
  29. child.type = 'button';
  30. child.name = 'copy-info-to-clipboard';
  31. child.setAttribute('class', 'btn btn-danger topframe_login');
  32. child.addEventListener("click", fetchAlbum, false);
  33. buttons[1].parentNode.insertBefore(child, buttons[1]);
  34. child = document.createTextNode(' ');
  35. buttons[1].parentNode.insertBefore(child, buttons[1]);
  36.  
  37. function fetchAlbum() {
  38. var matches, node, results, clipboard = '';
  39. var album_years, release_year;
  40. var track, tracks = [], totaldiscs = 1;
  41. var parser = new DOMParser();
  42. var req = new XMLHttpRequest();
  43. var button = document.getElementById('copy-info-to-clipboard');
  44. if (button != null) {
  45. button.disabled = true;
  46. var original_text = button.textContent;
  47. button.textContent = 'Pracuji...';
  48. }
  49. var album_artist = get_string('//h2[@class="album-artist"]/a/text()');
  50. var album = get_string('//h1[@itemprop="name"]/text()');
  51. var release_date = get_detail('Datum vydání');
  52. var genre = get_detail('Žánr');
  53. var label = get_detail('Vydavatel');
  54. var catalog = get_detail('Katalogové číslo');
  55. var desc = get_string('//div[@itemprop="description"]/p');
  56. var album_singers = get_album_artists('Stěžejní interpreti').sort((a, b) => a[1].localeCompare(b[1]));
  57. var album_groups = get_album_artists('Hudební tělesa').sort((a, b) => a.localeCompare(b));
  58. var album_composers = get_album_artists('Stěžejní autoři').sort((a, b) => a[1].localeCompare(b[1]));
  59. function get_album_artists(label) {
  60. var result = [];
  61. results = document.evaluate('//ul/li[h3[text() = "' + label + '"]]/following-sibling::li',
  62. document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  63. if (results.resultType == XPathResult.FIRST_ORDERED_NODE_TYPE) {
  64. results = results.singleNodeValue;
  65. while (results) {
  66. if (results.childNodes[0].tagName == 'SPAN') {
  67. result.push([
  68. results.childNodes[0].textContent.replace(/\s*:\s*$/, ''),
  69. results.childNodes[2].textContent,
  70. ]);
  71. } else if (results.childNodes[1].tagName == 'A') {
  72. result.push(results.childNodes[1].textContent);
  73. }
  74. results = results.nextSiblingElement;
  75. }
  76. return result;
  77. }
  78. return undefined;
  79. }
  80. if (desc) desc = desc.replace(/\r/g, '\\r').replace(/\n/g, '\\n');
  81. function get_string(xpath, html = document, root = html.body) {
  82. var node = html.evaluate(xpath, root, null, XPathResult.STRING_TYPE, null);
  83. return node.resultType == XPathResult.STRING_TYPE ? node.stringValue.trim() : undefined;
  84. }
  85. function get_detail(prop) {
  86. var base = '//ul[@class="summary"]/li[span[starts-with(text(), "' + prop + '")]]';
  87. return get_string(base + '/text()') || get_string(base + '/a/text()');
  88. }
  89. function get_node(xpath, html = document, root = html.body) {
  90. var node = html.evaluate(xpath, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  91. return node.resultType == XPathResult.FIRST_ORDERED_NODE_TYPE ? node.singleNodeValue : null;
  92. }
  93.  
  94. results = document.evaluate('//table[@class="table table-tracklist"]/tbody/tr[@itemprop="track"]',
  95. document.body, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
  96. while (node = results.iterateNext()) {
  97. let cdhdr = get_string('./preceding-sibling::tr[starts-with(@class, "cd-header")][1]/td/h3/text()', document, node);
  98. let discnumber = (matches = cdhdr.match(/^(?:CD|DVD)\s*(\d+)$/)) ? Number(matches[1]) : undefined;
  99. track = {
  100. id: node.id,
  101. discnumber: discnumber,
  102. tracknumber: node.childNodes[1].textContent.trim(),
  103. title: node.childNodes[5].textContent.trim(),
  104. duration: node.childNodes[7].textContent.trim(),
  105. performers: [],
  106. composers: [],
  107. directors: [],
  108. };
  109. if (matches = track.id.match(/^track-(\d+)$/)) track.id = matches[1];
  110. if (matches = track.tracknumber.match(/^(\d+)\.$/)) track.tracknumber = Number(matches[1]);
  111. req.open('GET', node.childNodes[5].childNodes[0].href, false);
  112. req.send();
  113. if (req.readyState == 4 && req.status == 200) {
  114. let html = parser.parseFromString(req.responseText, "text/html");
  115. var tr_det = get_node('//div[@data-swap="trackdetail-' + track.id + '"]/div/div[@class="row"]', html);
  116. if (tr_det != null) {
  117. track.album_year = Number(get_detail('Rok prvního vydání'));
  118. function get_detail(prop) {
  119. var base = './div/ul[@class="summary"]/li[span[starts-with(text(), "' + prop + '")]]';
  120. return get_string(base + '/text()', html, tr_det) || get_string(base + '/a/text()', html, tr_det);
  121. }
  122. let node, results = html.evaluate('./div[h4]/ul/li[span]',
  123. tr_det, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
  124. while (node = results.iterateNext()) {
  125. let prop = node.childNodes[1].textContent.trim().replace(/\s*:\s*$/, '');
  126. let val = node.childNodes[3].textContent.trim();
  127. if (['hudba', 'text', 'hudba+text', 'původní text', 'český text'].includes(prop)) {
  128. track.composers.push([prop, val]);
  129. } else if (['řídí'].includes(prop)) {
  130. track.directors.push([prop, val]);
  131. } else if (['produkce'].includes(prop)) {
  132. } else {
  133. track.performers.push([prop, val]);
  134. }
  135. function push_unique(prop, val) { if (!track[prop].includes(val)) track[prop].push(val); }
  136. }
  137. }
  138. }
  139. tracks.push(track);
  140. if (discnumber != undefined && discnumber > totaldiscs) totaldiscs = discnumber;
  141. }
  142. album_years = tracks.map(k => k.album_year);
  143. album_years = album_years.filter((item, pos) => album_years.indexOf(item) == pos);
  144. if (matches = release_date.match(/^(\d+)\.\s*(\d+)\.\s*(\d+)$/)) {
  145. release_year = Number(matches[3]);
  146. release_date = matches[3].padEnd(4, '0') + '-' + matches[2].padEnd(2, '0') + '-' + matches[1].padEnd(2, '0');
  147. }
  148. for (track of tracks.sort(function(a, b) {
  149. var k = a.discnumber - b.discnumber;
  150. return isNaN(k) || k == 0 ? a.tracknumber - b.tracknumber : k;
  151. })) {
  152. let track_artist = album_artist;
  153. let track_singers = track.performers.filter(k => k[0] == 'zpěv').sort((a, b) => a[1].localeCompare(b[1]));
  154. let track_groups = track.performers.filter(k => k[0] == 'hudební těleso').sort((a, b) => a[1].localeCompare(b[1])).map(k => k[1]);
  155. // test if track artists match album artist
  156. let same = true;
  157. if (album_groups.length > 0 && (album_groups.length != album_groups.length
  158. || !track_groups.every((k, ndx) => k == album_groups[ndx]))) same = false;
  159. if (same && (track_singers.length != album_singers.length
  160. || !track_singers.every((k, ndx) => k[1] == album_singers[ndx][1]))) same = false;
  161. if (!same) {
  162. track_groups = album_groups.length > 0 ? track.performers.filter(k => k[0] == 'hudební těleso').map(k => k[1]).join(', ') : '';
  163. track_singers = track.performers.filter(k => k[0] == 'zpěv').map(k => k[1]).join(', ');
  164. track_artist = track_groups + (track_groups && track_singers ? ', ' : '') + track_singers;
  165. }
  166. clipboard += [
  167. album_artist,
  168. album,
  169. album_years.length == 1 ? album_years[0] : release_year,
  170. release_date,
  171. genre,
  172. label,
  173. catalog,
  174. totaldiscs > 1 ? track.discnumber : undefined,
  175. totaldiscs > 1 ? totaldiscs : undefined,
  176. track.tracknumber,
  177. tracks.length,
  178. track_artist,
  179. track.title,
  180. track.performers.map(k => k[1] + (['Artist', 'Umělec', 'hudební těleso'].includes(k[0]) ? '' : ' (' + k[0] + ')')).join(', '),
  181. track.composers.map(k => k[1] + ' (' + k[0] + ')').join(', '),
  182. desc,
  183. document.URL.replace(/\?.*/, ''),
  184. ].join('\x1E') + '\n';
  185. }
  186. GM_setClipboard(clipboard, 'text');
  187. if (button != null) {
  188. button.disabled = false;
  189. button.textContent = original_text;
  190. }
  191. }