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-06 提交的版本,查看 最新版本

// ==UserScript==
// @name         Supraphon Online: Fetch album info to clipboard
// @namespace    https://greasyfork.org/cs/users/321857-anakunda
// @version      1.0
// @description  Zkopíruje playlist do schránky tak aby jej bylo možno v hudebním přehrávači aplikovat na tagy
// @author       Já, Osobně
// @match        https://www.supraphonline.cz/album/*
// @match        http://www.supraphonline.cz/album/*
// @run-at       document-idle
// @grant        RegExp
// @grant        GM_getValue
// @grant        GM_getValue
// @grant        GM_setClipboard
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @grant        GM.xmlHttpRequest
// ==/UserScript==

// Výraz pro 'Automatically Fill Values" funkci ve foobaru2000:
//   %album artist%%album%%date%%releasedate%%genre%%label%%catalog%%discnumber%%totaldiscs%%discsubtitle%%tracknumber%%totaltracks%%artist%%title%%performer%%composer%%comment%%url%

'use strict';

var buttons = document.getElementsByName('buy');
if (buttons == null) return;
var child = document.createElement('button');
child.id = 'copy-info-to-clipboard';
child.textContent = 'Kopírovat do schránky';
child.type = 'button';
child.name = 'copy-info-to-clipboard';
child.setAttribute('class', 'btn btn-danger topframe_login');
child.addEventListener("click", fetchAlbum, false);
buttons[1].parentNode.insertBefore(child, buttons[1]);
child = document.createTextNode(' ');
buttons[1].parentNode.insertBefore(child, buttons[1]);

function fetchAlbum() {
  var matches, node, results, clipboard = '';
  var album_years, release_year;
  var track, tracks = [], totaldiscs = 1;
  var parser = new DOMParser();
  var req = new XMLHttpRequest();
  var button = document.getElementById('copy-info-to-clipboard');
  if (button != null) {
	button.disabled = true;
	var original_text = button.textContent;
	button.textContent = 'Pracuji...';
  }
  var album_artist = get_string('//h2[@class="album-artist"]/a/text()');
  var album = get_string('//h1[@itemprop="name"]/text()');
  var release_date = get_detail('Datum vydání');
  var genre = get_detail('Žánr');
  var label = get_detail('Vydavatel');
  var catalog = get_detail('Katalogové číslo');
  var desc = get_string('//div[@itemprop="description"]/p');
  var album_performers = get_album_artists('Stěžejní interpreti').sort((a, b) => a[1].localeCompare(b[1]));
  var album_ensembles = get_album_artists('Hudební tělesa').sort((a, b) => a.localeCompare(b));
  var album_composers = get_album_artists('Stěžejní autoři').sort((a, b) => a[1].localeCompare(b[1]));
  var pivot_tags = ['Artist', 'Umělec', 'zpěv', 'hraje'];
  function isPivotTag(val) { val = val.toLowerCase(); return pivot_tags.some(k => k.toLowerCase() == val) }
  album_performers.forEach(function(k) { if (!isPivotTag(k[0])) { pivot_tags.push(k[0]) }});
  function get_album_artists(label) {
	var result = [];
	results = document.evaluate('//ul/li[h3[text() = "' + label + '"]]/following-sibling::li',
								document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
	if (results.resultType == XPathResult.FIRST_ORDERED_NODE_TYPE) {
	  results = results.singleNodeValue;
	  while (results) {
		if (results.childNodes[0].tagName == 'SPAN') {
		  result.push([
			results.childNodes[0].textContent.replace(/\s*:\s*$/, ''),
			results.childNodes[2].textContent,
		  ]);
		} else if (results.childNodes[1].tagName == 'A') {
		  result.push(results.childNodes[1].textContent);
		}
		results = results.nextSiblingElement;
	  }
	  return result;
	}
	return undefined;
  }
  if (desc) desc = desc.replace(/\r/g, '\\r').replace(/\n/g, '\\n');
  function get_string(xpath, html = document, root = html.body) {
	var node = html.evaluate(xpath, root, null, XPathResult.STRING_TYPE, null);
	return node.resultType == XPathResult.STRING_TYPE ? node.stringValue.trim() : undefined;
  }
  function get_detail(prop) {
	var base = '//ul[@class="summary"]/li[span[starts-with(text(), "' + prop + '")]]';
	return get_string(base + '/text()') || get_string(base + '/a/text()');
  }
  function get_node(xpath, html = document, root = html.body) {
	var node = html.evaluate(xpath, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
	return node.resultType == XPathResult.FIRST_ORDERED_NODE_TYPE ? node.singleNodeValue : null;
  }

  results = document.evaluate('//table[@class="table table-tracklist"]/tbody/tr[@itemprop="track"]',
	document.body, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
  while (node = results.iterateNext()) {
	let vol_hdr = get_string('./preceding-sibling::tr[starts-with(@class, "cd-header")][1]/td/h3/text()', document, node);
	let song_hdr = get_string('./preceding-sibling::tr[@class="song-header"][1]/td/text()', document, node);
	let discnumber = (matches = vol_hdr.match(/^(?:CD|DVD|LP)\s*(\d+)$/)) ? Number(matches[1]) : undefined;
	track = {
	  id: node.id,
	  discnumber: discnumber,
	  tracknumber: node.childNodes[1].textContent.trim(),
	  discsubtitle: song_hdr,
	  title: node.childNodes[5].textContent.trim(),
	  duration: node.childNodes[7].textContent.trim(),
	  performers: [],
	  composers: [],
	  directors: [],
	};
	if (matches = track.id.match(/^track-(\d+)$/)) track.id = matches[1];
	if (matches = track.tracknumber.match(/^(\d+)\.$/)) track.tracknumber = Number(matches[1]);
	req.open('GET', node.childNodes[5].childNodes[0].href, false);
	req.send();
	if (req.readyState == 4 && req.status == 200) {
	  let html = parser.parseFromString(req.responseText, "text/html");
	  let tr_det = get_node('//div[@data-swap="trackdetail-' + track.id + '"]/div/div[@class="row"]', html);
	  if (tr_det != null) {
		track.album_year = Number(get_detail('Rok prvního vydání'));
		track.genre = get_detail('Žánr');
		track.place = get_detail('Místo nahrání')
		track.finished = get_detail('Nahrávka dokončena')
		function get_detail(prop) {
		  var base = './div/ul[@class="summary"]/li[span[starts-with(text(), "' + prop + '")]]';
		  return get_string(base + '/text()', html, tr_det) || get_string(base + '/a/text()', html, tr_det);
		}
		let node, results = html.evaluate('./div[h4]/ul/li[span]',
			tr_det, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
		while (node = results.iterateNext()) {
		  let prop = node.childNodes[1].textContent.trim().replace(/\s*:\s*$/, '');
		  let val = node.childNodes[3].textContent.trim();
		  if (['hudba', 'text', 'hudba+text', 'původní text', 'český text', 'libreto'].includes(prop)) {
			track.composers.push([prop, val]);
		  } else if (['nahrál'].includes(prop)) {
		  } else if (['dirigent', 'řídí'].includes(prop)) {
			track.directors.push([prop, val]);
		  } else if (['produkce'].includes(prop)) {
		  } else {
			track.performers.push([prop, val]);
		  }
		  function push_unique(prop, val) { if (!track[prop].includes(val)) track[prop].push(val); }
		}
	  }
	}
	tracks.push(track);
	if (typeof discnumber == 'number' && discnumber > totaldiscs) totaldiscs = discnumber;
  }
  album_years = tracks.map(k => k.album_year);
  album_years = album_years.filter((item, pos) => album_years.indexOf(item) == pos);
  if (matches = release_date.match(/^(\d+)\.\s*(\d+)\.\s*(\d+)$/)) {
	release_year = Number(matches[3]);
	release_date = matches[3].padStart(4, '0') + '-' + matches[2].padStart(2, '0') + '-' + matches[1].padStart(2, '0');
  }
  for (track of tracks.sort(function(a, b) {
	var k = a.discnumber - b.discnumber;
	return Number.isNaN(k) || k == 0 ? a.tracknumber - b.tracknumber : k;
  })) {
	let track_artist = album_artist;
	let track_performers = track.performers.filter(k => isPivotTag(k[0])).map(k => k[1]);
	let track_ensembles = track.performers.filter(k => k[0] == 'hudební těleso').map(k => k[1]);
	// test if track artists match album artist
	function sort_func(a, b) { return a.localeCompare(b) }
	if (album_ensembles.length > 0 && (track_ensembles.length != album_ensembles.length
		|| !track_ensembles.sort(sort_func).every((k, ndx) => k == album_ensembles[ndx]))
		|| track_performers.length != album_performers.length
		|| !track_performers.sort(sort_func).every((k, ndx) => k == album_performers[ndx])) {
	  let track_artists = track_performers;
	  if (album_ensembles.length > 0) track_artists.push(...track_ensembles);
	  track_artist = track_artists.join(', ');
	  if (!track_artist) track_artist = album_artist; // unknown musician mapping
	}
	clipboard += [
	  album_artist,
	  album,
	  album_years.length == 1 ? album_years[0] : release_year,
	  release_date,
	  track.genre || genre,
	  label,
	  catalog,
	  totaldiscs > 1 ? track.discnumber : undefined,
	  totaldiscs > 1 ? totaldiscs : undefined,
	  track.discsubtitle,
	  track.tracknumber,
	  tracks.length, //tracks.filter(k => k.discnumber === track.discnumber).length,
	  track_artist,
	  track.title,
	  track.performers.map(k => k[1] + (['Artist', 'Umělec', 'hudební těleso'].includes(k[0]) ? '' : ' (' + k[0] + ')')).join(', '),
	  track.composers.map(k => k[1] + ' (' + k[0] + ')').join(', '),
	  desc,
	  document.URL.replace(/\?.*/, ''),
	].join('\x1E') + '\n';
  }
  GM_setClipboard(clipboard, 'text');
  if (button != null) {
	button.disabled = false;
	button.textContent = original_text;
  }
  return;

  function join_artists(list) {
	return list.length > 1 ? list.slice(0, -1).join(', ') + ' a ' + list[list.length - 1] : list;
  }
}