32
32
const TitleRemixRegexp =
33
33
/ ^ \s * ( .+ ) \s + \( \s * ( .+ ) \s + (?: (?: r e - ? ) ? (?: [ d r ] u b | e d i t | m i x ) | r e - ? (?: m o d e l | s h u f f l e | w o r k ) ) .* \) / i;
34
34
35
+ /* Examples of track titles this regex should match:
36
+ *
37
+ * Iceolate (12″ extended mix)
38
+ * Zone 12 (extended mix)
39
+ * Punks in the City (disco edit)
40
+ * Individualists (7inch version)
41
+ * Wicked Games (radio edit)
42
+ * Respectness (dub version)
43
+ * Barcelona (extended version)
44
+ */
45
+ const TitleEditRegexp =
46
+ / ^ \s * ( .+ ) \s + \( \s * (?: (?: (?: 7 | 1 0 | 1 2 ) \s * (?: [ ' " ″ ) ] | i n c h ) ? ) ? \s * (?: e x t e n d e d | d i s c o | d u b | r a d i o ) ? \s * (?: e d i t | m i x | v e r s i o n ) ) \s * \) / i;
47
+
35
48
// This code is based on:
36
49
// https://stackoverflow.com/questions/42795059/programmatically-fill-reactjs-form
37
50
function setElementValue ( element , value , event = 'input' ) {
@@ -75,24 +88,32 @@ function addRemixCreditLinks() {
75
88
76
89
for ( const recording of recordings ) {
77
90
const title = recording . querySelector ( 'bdi' ) . innerText ;
78
- const matches = TitleRemixRegexp . exec ( title ) ;
79
- if ( matches === null ) {
91
+ const remixMatches = TitleRemixRegexp . exec ( title ) ;
92
+ const editMatches = TitleEditRegexp . exec ( title ) ;
93
+ if ( ! remixMatches && ! editMatches ) {
80
94
continue ;
81
95
}
82
96
83
- const linkTypes = { } ;
97
+ let linkTypes = { } ;
84
98
// find existing relationship types for this recording
85
99
for ( const link of recording . getElementsByClassName ( 'link-phrase' ) ) {
86
100
linkTypes [ link . innerText ] = 1 ;
87
101
}
88
102
103
+ let trackArtists = Array . from (
104
+ recording . querySelectorAll ( 'td > a[href^="/artist"] bdi' )
105
+ ) . map ( bdi => bdi . innerText ) ;
106
+ if ( ! trackArtists . length ) {
107
+ trackArtists = releaseArtists ;
108
+ }
109
+
89
110
let button = document . createElement ( 'button' ) ;
90
- if ( linkTypes [ 'remixer:' ] ) {
111
+ if ( ! remixMatches || linkTypes [ 'remixer:' ] ) {
91
112
button . className = 'add-item with-label btn disabled' ;
92
- } else {
113
+ } else if ( remixMatches ) {
93
114
button . className = 'add-item with-label' ;
94
115
button . onclick = addRemixCreditClickHandler ;
95
- button . setAttribute ( 'data-remixer' , matches [ 2 ] ) ;
116
+ button . setAttribute ( 'data-remixer' , remixMatches [ 2 ] ) ;
96
117
}
97
118
98
119
button . innerHTML = `
@@ -102,17 +123,13 @@ function addRemixCreditLinks() {
102
123
recording . appendChild ( document . createTextNode ( '\n' ) ) ;
103
124
104
125
button = document . createElement ( 'button' ) ;
105
- if ( linkTypes [ 'remix of:' ] ) {
126
+ if ( ! remixMatches || linkTypes [ 'remix of:' ] ) {
106
127
button . className = 'add-item with-label btn disabled' ;
107
- } else {
108
- let trackArtists = Array . from (
109
- recording . querySelectorAll ( 'td > a[href^="/artist"] bdi' )
110
- ) . map ( bdi => bdi . innerText ) ;
111
- if ( ! trackArtists . length ) {
112
- trackArtists = releaseArtists ;
113
- }
128
+ } else if ( remixMatches ) {
114
129
// recording search will be pre-filled with title and artists to improve the results
115
- const recordingQuery = `${ matches [ 1 ] } ${ trackArtists . join ( ' ' ) } ` ;
130
+ const recordingQuery = `${ remixMatches [ 1 ] } ${ trackArtists . join (
131
+ ' '
132
+ ) } `;
116
133
117
134
button . className = 'add-item with-label' ;
118
135
button . onclick = addRemixCreditClickHandler ;
@@ -123,6 +140,25 @@ function addRemixCreditLinks() {
123
140
Add "remix of" credit
124
141
` ;
125
142
recording . appendChild ( button ) ;
143
+
144
+ button = document . createElement ( 'button' ) ;
145
+ if ( ! editMatches || linkTypes [ 'edit of:' ] ) {
146
+ button . className = 'add-item with-label btn disabled' ;
147
+ } else if ( editMatches ) {
148
+ // recording search will be pre-filled with title and artists to improve the results
149
+ const recordingQuery = `${ editMatches [ 1 ] } ${ trackArtists . join (
150
+ ' '
151
+ ) } `;
152
+
153
+ button . className = 'add-item with-label' ;
154
+ button . onclick = addRemixCreditClickHandler ;
155
+ button . setAttribute ( 'data-edit-of' , recordingQuery ) ;
156
+ }
157
+
158
+ button . innerHTML = `
159
+ Add "edit of" credit
160
+ ` ;
161
+ recording . appendChild ( button ) ;
126
162
}
127
163
}
128
164
@@ -132,6 +168,7 @@ function addRemixCreditClickHandler(event) {
132
168
const recording = this . parentElement ;
133
169
const remixer = this . getAttribute ( 'data-remixer' ) ;
134
170
const remixOf = this . getAttribute ( 'data-remix-of' ) ;
171
+ const editOf = this . getAttribute ( 'data-edit-of' ) ;
135
172
136
173
const addRel = recording . querySelector ( 'button.add-relationship' ) ;
137
174
addRel . click ( ) ;
@@ -157,7 +194,7 @@ function addRemixCreditClickHandler(event) {
157
194
} , 100 ) ;
158
195
}
159
196
} , 250 ) ;
160
- } else if ( remixOf ) {
197
+ } else if ( remixOf || editOf ) {
161
198
// wait 250ms for the dialog to be added to the DOM
162
199
window . setTimeout ( function ( ) {
163
200
const dialog = document . getElementById ( 'add-relationship-dialog' ) ;
@@ -169,11 +206,14 @@ function addRemixCreditClickHandler(event) {
169
206
const linkType = dialog . querySelector (
170
207
'input.relationship-type'
171
208
) ;
172
- setElementValue ( linkType , 'remix of / has remixes' ) ;
209
+ setElementValue (
210
+ linkType ,
211
+ remixOf ? 'remix of / has remixes' : 'edit of / edits'
212
+ ) ;
173
213
tabToConfirmFirstOption ( linkType ) ;
174
214
175
215
const name = dialog . querySelector ( 'input.relationship-target' ) ;
176
- setElementValue ( name , remixOf ) ;
216
+ setElementValue ( name , remixOf || editOf ) ;
177
217
const search =
178
218
name . parentElement . querySelector ( 'button.search' ) ;
179
219
if ( search ) {
0 commit comments