Skip to content

Commit f6d6323

Browse files
authored
Merge pull request #181 from gustavkj/update-remixer-script
Update add remix credit links to work with current MB interface
2 parents faffb3e + 9938e8e commit f6d6323

File tree

1 file changed

+69
-61
lines changed

1 file changed

+69
-61
lines changed

mb_add_remix_credit_links.user.js

+69-61
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@
2828
* The Rainbow Song (Crackazat rework)
2929
*/
3030
const TitleRemixRegexp =
31-
/^\s*(.+)\s+\(\s*(.+)\s+(?:(?:re)?mix|re-?(?:[dr]ub|edit|work)|edit).*\)/i;
32-
33-
const AddIconUri = 'https://staticbrainz.org/MB/add-e585eab.png';
34-
// <option value="153">&nbsp;&nbsp;remixer</option>
35-
const RemixerOptionValue = '153';
36-
// <option value="230">&nbsp;&nbsp;remix of</option>
37-
const RemixOfOptionValue = '230';
31+
/^\s*(.+)\s+\(\s*(.+)\s+(?:(?:re-?)?(?:[dr]ub|edit|mix)|re-?work).*\)/i;
3832

3933
// This code is based on:
4034
// https://stackoverflow.com/questions/42795059/programmatically-fill-reactjs-form
@@ -60,17 +54,19 @@ function setElementValue(element, value, event = 'input') {
6054
element.dispatchEvent(new Event(event, { bubbles: true }));
6155
}
6256

63-
function addStyleElement() {
64-
const style = document.createElement('style');
65-
style.type = 'text/css';
66-
document.head.appendChild(style);
67-
style.appendChild(
68-
document.createTextNode('.add-rc { display: inline-block; }')
69-
);
57+
function tabToConfirmFirstOption(element) {
58+
const event = new KeyboardEvent('keydown', {
59+
key: 'Tab',
60+
keyCode: 9,
61+
which: 9,
62+
bubbles: true,
63+
cancelable: true,
64+
});
65+
element.dispatchEvent(event);
7066
}
7167

7268
function addRemixCreditLinks() {
73-
const recordings = document.getElementsByClassName('recording');
69+
const recordings = document.querySelectorAll('td.recording');
7470
const releaseArtists = Array.from(
7571
document
7672
.getElementsByClassName('subheader')[0]
@@ -92,47 +88,46 @@ function addRemixCreditLinks() {
9288
linkTypes[link.innerText] = 1;
9389
}
9490

95-
let span = document.createElement('span');
96-
if (linkTypes['remixer']) {
97-
span.className = 'add-rc btn disabled';
91+
let button = document.createElement('button');
92+
if (linkTypes['remixer:']) {
93+
button.className = 'add-item with-label btn disabled';
9894
} else {
99-
span.className = 'add-rc btn';
100-
span.onclick = addRemixCreditClickHandler;
101-
span.setAttribute('data-remixer', matches[2]);
95+
button.className = 'add-item with-label';
96+
button.onclick = addRemixCreditClickHandler;
97+
button.setAttribute('data-remixer', matches[2]);
10298
}
10399

104-
span.innerHTML = `
105-
<img class="bottom" src="${AddIconUri}">
100+
button.innerHTML = `
106101
Add "remixer" credit
107102
`;
108-
recording.appendChild(span);
103+
recording.appendChild(button);
109104
recording.appendChild(document.createTextNode('\n'));
110105

111-
span = document.createElement('span');
112-
if (linkTypes['remix of']) {
113-
span.className = 'add-rc btn disabled';
106+
button = document.createElement('button');
107+
if (linkTypes['remix of:']) {
108+
button.className = 'add-item with-label btn disabled';
114109
} else {
115-
let trackArtists = Array.from(
116-
recording
117-
.getElementsByTagName('span')[1]
118-
.getElementsByTagName('bdi')
119-
).map(bdi => bdi.innerText);
110+
const trackArtistElement = recording
111+
.getElementsByTagName('span')[1];
112+
113+
let trackArtists = trackArtistElement ? Array.from(
114+
trackArtistElement.getElementsByTagName('bdi')
115+
).map(bdi => bdi.innerText) : [];
120116
if (!trackArtists.length) {
121117
trackArtists = releaseArtists;
122118
}
123119
// recording search will be pre-filled with title and artists to improve the results
124120
const recordingQuery = `${matches[1]} ${trackArtists.join(' ')}`;
125121

126-
span.className = 'add-rc btn';
127-
span.onclick = addRemixCreditClickHandler;
128-
span.setAttribute('data-remix-of', recordingQuery);
122+
button.className = 'add-item with-label';
123+
button.onclick = addRemixCreditClickHandler;
124+
button.setAttribute('data-remix-of', recordingQuery);
129125
}
130126

131-
span.innerHTML = `
132-
<img class="bottom" src="${AddIconUri}">
127+
button.innerHTML = `
133128
Add "remix of" credit
134129
`;
135-
recording.appendChild(span);
130+
recording.appendChild(button);
136131
}
137132
}
138133

@@ -143,48 +138,61 @@ function addRemixCreditClickHandler(event) {
143138
const remixer = this.getAttribute('data-remixer');
144139
const remixOf = this.getAttribute('data-remix-of');
145140

146-
const addRel = recording.getElementsByClassName('add-rel')[0];
141+
const addRel = recording.querySelector('button.add-relationship');
147142
addRel.click();
148143

149144
if (remixer) {
150145
// wait 250ms for the dialog to be added to the DOM
151146
window.setTimeout(function () {
152-
const dialog = document.getElementById('dialog');
153-
const linkType = dialog.getElementsByClassName('link-type')[0];
154-
setElementValue(linkType, RemixerOptionValue, 'change');
155-
156-
const name = dialog.getElementsByClassName('name')[0];
157-
if (remixer) {
158-
setElementValue(name, remixer);
159-
} else {
160-
name.focus();
147+
const dialog = document.getElementById('add-relationship-dialog');
148+
const entityType = dialog.querySelector('select.entity-type');
149+
setElementValue(entityType, 'artist', 'change');
150+
151+
const linkType = dialog.querySelector('input.relationship-type');
152+
setElementValue(linkType, 'remixed / remixer');
153+
tabToConfirmFirstOption(linkType);
154+
155+
const name = dialog.querySelector('input.relationship-target');
156+
setElementValue(name, remixer);
157+
const search = name.parentElement.querySelector('button.search');
158+
if (search) {
159+
window.setTimeout(function() {
160+
search.click();
161+
name.focus();
162+
}, 100);
161163
}
162164
}, 250);
163165
} else if (remixOf) {
164166
// wait 250ms for the dialog to be added to the DOM
165167
window.setTimeout(function () {
166-
const dialog = document.getElementById('dialog');
167-
const entityType = dialog.getElementsByClassName('entity-type')[0];
168+
const dialog = document.getElementById('add-relationship-dialog');
169+
const entityType = dialog.querySelector('select.entity-type');
168170
setElementValue(entityType, 'recording', 'change');
169171

170172
// wait another 250ms for the link-type select options to be updated
171173
window.setTimeout(function () {
172-
const linkType = dialog.getElementsByClassName('link-type')[0];
173-
setElementValue(linkType, RemixOfOptionValue, 'change');
174-
175-
const name = dialog.getElementsByClassName('name')[0];
176-
if (remixOf) {
177-
setElementValue(name, remixOf);
178-
} else {
179-
name.focus();
174+
const linkType = dialog.querySelector('input.relationship-type');
175+
setElementValue(linkType, 'remix of / has remixes');
176+
tabToConfirmFirstOption(linkType);
177+
178+
const name = dialog.querySelector('input.relationship-target');
179+
setElementValue(name, remixOf);
180+
const search = name.parentElement.querySelector('button.search');
181+
if (search) {
182+
window.setTimeout(function() {
183+
search.click();
184+
name.focus();
185+
}, 100);
180186
}
181187
}, 250);
182188
}, 250);
183189
}
184190
}
185191

186192
// wait 500ms for the page to fully initialise
187-
window.setTimeout(function () {
188-
addStyleElement();
189-
addRemixCreditLinks();
193+
const intervalId = window.setInterval(function () {
194+
if (!document.querySelector('.loading-message')) {
195+
window.clearInterval(intervalId);
196+
addRemixCreditLinks();
197+
}
190198
}, 500);

0 commit comments

Comments
 (0)