Skip to content

Commit e43f8e6

Browse files
committed
fix: switch to @include rules because @match is too limited
https://youtu.be/v7NOGSwXh7U?t=16
1 parent c08fe6c commit e43f8e6

File tree

12 files changed

+163
-97
lines changed

12 files changed

+163
-97
lines changed

build/plugin-userscript.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const DEFAULT_OPTIONS = {
3030
metadataOrder: [
3131
'name', 'description', 'version', 'author', 'license', 'namespace',
3232
'homepageURL', 'supportURL', 'downloadURL', 'updateURL',
33-
'match', 'exclude', 'require', 'resource', 'run-at', 'grant', 'connect',
33+
'include', 'exclude', 'require', 'resource', 'run-at', 'grant', 'connect',
3434
],
3535
};
3636

src/lib/util/metadata.ts

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
export interface UserscriptCustomMetadata {
66
name: string;
77
description: string;
8-
match: readonly string[] | string;
8+
include: readonly string[] | string;
99
exclude?: readonly string[] | string;
1010
require?: readonly string[] | string;
1111
// https://wiki.greasespot.net/Metadata_Block#.40run-at
@@ -28,17 +28,104 @@ export interface UserscriptDefaultMetadata {
2828
export type UserscriptMetadata = UserscriptCustomMetadata & Partial<UserscriptDefaultMetadata>;
2929
export type AllUserscriptMetadata = UserscriptCustomMetadata & UserscriptDefaultMetadata & { version: string };
3030

31+
// Borrowed and adapted from kellnerd
32+
// https://github.com/kellnerd/musicbrainz-bookmarklets/blob/730ed0f96a81ef9bb239ed564f247bd68f84bee3/tools/userscriptMetadata.js#L68
33+
interface CreateURLRuleRegexOptions {
34+
query?: 'mandatory' | 'forbidden' | 'allowed';
35+
fragment?: 'mandatory' | 'forbidden' | 'allowed';
36+
}
37+
38+
const MB_DOMAIN_REGEX = /(\w+\.)?musicbrainz\.org/;
39+
40+
function constructSuffix({
41+
query = 'allowed',
42+
fragment = 'allowed',
43+
}: CreateURLRuleRegexOptions): string {
44+
// Short circuit for shorter regexes
45+
if (query === 'allowed' && fragment === 'allowed') {
46+
return '([?#]|$)';
47+
}
48+
49+
let suffix = '';
50+
if (query === 'mandatory') {
51+
suffix += String.raw`\?.+?`;
52+
} else if (query === 'allowed') {
53+
suffix += String.raw`(\?.+?)?`;
54+
}
55+
56+
if (fragment === 'mandatory') {
57+
suffix += '#.+?';
58+
} else if (fragment === 'allowed') {
59+
suffix += '(#.+?)?';
60+
}
61+
62+
return suffix + '$';
63+
}
64+
65+
export function createURLRuleRegex(domainPattern: string | RegExp, pathRegex: string | RegExp, options: CreateURLRuleRegexOptions = {}): string {
66+
const domainRegex = typeof domainPattern !== 'string' ? domainPattern.source : domainPattern.replaceAll('.', '\\.');
67+
pathRegex = (typeof pathRegex === 'string') ? pathRegex : pathRegex.source;
3168

32-
export function transformMBMatchURL(requireString: string): string {
33-
return `*://*.musicbrainz.org/${requireString}`;
69+
return `/^https?://${domainRegex}/${pathRegex}${constructSuffix(options)}/`;
3470
}
3571

72+
function removeTemplateAndCreateRule(options: CreateURLRuleRegexOptions, pattern: string): string;
73+
function removeTemplateAndCreateRule(options: CreateURLRuleRegexOptions, template: TemplateStringsArray, ...values: string[]): string;
74+
function removeTemplateAndCreateRule(options: CreateURLRuleRegexOptions, pattern: string | TemplateStringsArray, ...values: string[]): string {
75+
if (typeof pattern === 'string') {
76+
return createURLRuleRegex(MB_DOMAIN_REGEX, pattern, options);
77+
} else {
78+
const fullPattern = pattern.raw[0] + pattern.raw.slice(1)
79+
.map((lit, idx) => `${values[idx]}${lit}`)
80+
.join('');
81+
return createURLRuleRegex(MB_DOMAIN_REGEX, fullPattern, options);
82+
}
83+
}
84+
85+
// To be used with a tagged template literal
86+
export function createMBRegex(options: CreateURLRuleRegexOptions): (pattern: string | TemplateStringsArray) => string;
87+
export function createMBRegex(pattern: string): string;
88+
export function createMBRegex(pattern: TemplateStringsArray, ...values: string[]): string;
89+
export function createMBRegex(patternOrOptions: CreateURLRuleRegexOptions | string | TemplateStringsArray, ...values: string[]): ((pattern: string) => string) | ((pattern: TemplateStringsArray, ...values2: string[]) => string) | string {
90+
// The two first branches could in practice be merged, but TypeScript struggles with that.
91+
if (typeof patternOrOptions === 'string') {
92+
return removeTemplateAndCreateRule({}, patternOrOptions);
93+
} else if (Array.isArray(patternOrOptions)) {
94+
return removeTemplateAndCreateRule({}, patternOrOptions as TemplateStringsArray, ...values);
95+
} else {
96+
return removeTemplateAndCreateRule.bind(undefined, patternOrOptions as CreateURLRuleRegexOptions);
97+
}
98+
}
99+
100+
const mb = createMBRegex;
101+
export const MBID_REGEX_PART = String.raw`[a-f\d-]{36}`;
102+
const mbid = MBID_REGEX_PART;
103+
104+
// List again -stolen- borrowed from kellnerd. Genre doesn't have an edit history.
105+
export const MB_EDITABLE_ENTITIES = [
106+
'area',
107+
'artist',
108+
'event',
109+
'instrument',
110+
'label',
111+
'place',
112+
'recording',
113+
'release',
114+
'release-group',
115+
'series',
116+
'work',
117+
'url',
118+
];
119+
36120
/** Any pages on which edits can occur */
37-
export const MB_EDIT_PAGE_PATHS = [
38-
'edit/*',
39-
// <entity>/<entity_id>/edits, user/<username>/edits/open, search/edits?condition.0=..., ...
40-
// TODO: This also matches /search/edits, on which no edits are shown. Should somehow be excluded
41-
'*/edits*',
42-
'user/*/votes',
43-
'*/open_edits',
121+
export const MB_EDIT_DISPLAY_PAGE_PATTERNS = [
122+
mb`edit/\d+`,
123+
// <entity>/<entity_id>/edits, <entity>/<entity_id>/open_edits
124+
mb`(${MB_EDITABLE_ENTITIES.join('|')})/${mbid}/(open_)?edits`,
125+
// user/<username>/edits/...
126+
mb`user/[^/]+/edits(/\w+)?`,
127+
// user/<username>/votes
128+
mb`user/[^/]+/votes`,
129+
// Edit search
130+
mb({ query: 'mandatory' })`search/edits`,
44131
];

src/mb_blind_votes/meta.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { MB_EDIT_PAGE_PATHS, transformMBMatchURL } from '@lib/util/metadata';
2+
import { MB_EDIT_DISPLAY_PAGE_PATTERNS } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: Blind Votes',
66
description: 'Blinds editor details before your votes are cast.',
77
// FIXME: This should run at document-start to ensure that editor details
88
// don't flash onto the screen while the page is still loading.
99
'run-at': 'document-end',
10-
match: MB_EDIT_PAGE_PATHS.map((path) => transformMBMatchURL(path)),
10+
include: MB_EDIT_DISPLAY_PAGE_PATTERNS,
1111
};
1212

1313
export default metadata;

src/mb_caa_dimensions/meta.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { MB_EDIT_PAGE_PATHS, transformMBMatchURL } from '@lib/util/metadata';
2+
import { createMBRegex as mb, MB_EDIT_DISPLAY_PAGE_PATTERNS, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: Display CAA image dimensions',
66
description: 'Displays the dimensions and size of images in the cover art archive.',
77
'run-at': 'document-start',
8-
match: [
9-
'release/*',
10-
'release-group/*',
11-
...MB_EDIT_PAGE_PATHS,
12-
].map((path) => transformMBMatchURL(path)),
8+
include: [
9+
...MB_EDIT_DISPLAY_PAGE_PATTERNS,
10+
mb`release(-group)?/${mbid}(/.+?)?`,
11+
],
1312
exclude: [
14-
transformMBMatchURL('release/*/edit'),
15-
transformMBMatchURL('release/*/edit-relationships'),
16-
transformMBMatchURL('release-group/*/edit'),
13+
mb`release(-group)?/${mbid}/edit`,
14+
mb`release-group/${mbid}/edit-relationships`,
1715
],
1816
};
1917

src/mb_enhanced_cover_art_uploads/meta.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { transformMBMatchURL } from '@lib/util/metadata';
3-
4-
const mbMatchedUrls = [
5-
'release/*/add-cover-art',
6-
'release/*/add-cover-art?*',
7-
'release/*/cover-art',
8-
].map((url) => transformMBMatchURL(url));
2+
import { createMBRegex as mb, createURLRuleRegex, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
93

104
const metadata: UserscriptMetadata = {
115
name: 'MB: Enhanced Cover Art Uploads',
126
description: 'Enhance the cover art uploader! Upload directly from a URL, automatically import covers from Discogs/Spotify/Apple Music/..., automatically retrieve the largest version, and more!',
137
'run-at': 'document-end',
14-
match: [
15-
...mbMatchedUrls,
16-
'*://atisket.pulsewidth.org.uk/*',
17-
'*://etc.marlonob.info/atisket/*',
18-
'*://vgmdb.net/album/*',
8+
include: [
9+
mb`release/${mbid}/add-cover-art`,
10+
mb`release/${mbid}/cover-art`,
11+
createURLRuleRegex('atisket.pulsewidth.org.uk/', /.*?/, { query: 'mandatory' }),
12+
createURLRuleRegex('etc.marlonob.info', /atisket\/.*?/, { query: 'mandatory' }),
13+
createURLRuleRegex('vgmdb.net', /album\/\d+/),
1914
],
20-
exclude: ['*://atisket.pulsewidth.org.uk/'],
2115
grant: [
2216
'GM.xmlhttpRequest',
2317
// Used for some favicons
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { transformMBMatchURL } from '@lib/util/metadata';
2+
import { createMBRegex as mb, MB_EDITABLE_ENTITIES, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: QoL: Paste multiple external links at once',
66
description: 'Enables pasting multiple links, separated by whitespace, into the external link editor.',
77
'run-at': 'document-end',
8-
match: [
9-
'*/edit',
10-
'*/edit?*',
11-
'release/*/edit-relationships*',
12-
'*/add',
13-
'*/add?*',
14-
'*/create',
15-
'*/create?*',
16-
].map((path) => transformMBMatchURL(path)),
8+
include: [
9+
mb`(${MB_EDITABLE_ENTITIES.join('|')})/(add|create|${mbid}/edit)`,
10+
mb`release/${mbid}/edit-relationships`,
11+
],
1712
};
1813

1914
export default metadata;
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { transformMBMatchURL } from '@lib/util/metadata';
2+
import { createMBRegex as mb, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
// FIXME: This name isn't very descriptive.
66
name: 'MB: QoL: Inline all recordings\' tracks on releases',
77
description: 'Display all tracks and releases on which a recording appears from the release page.',
88
'run-at': 'document-end',
9-
match: transformMBMatchURL('release/*'),
10-
exclude: [
11-
transformMBMatchURL('release/add'),
12-
transformMBMatchURL('release/*/edit*'),
13-
],
9+
include: mb`release/${mbid}`,
1410
};
1511

1612
export default metadata;
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { transformMBMatchURL } from '@lib/util/metadata';
2+
import { createMBRegex as mb, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: QoL: Seed the batch recording comments script',
66
description: 'Seed the recording comments for the batch recording comments userscripts with live and DJ-mix data.',
77
'run-at': 'document-end',
8-
match: transformMBMatchURL('release/*'),
9-
exclude: [
10-
transformMBMatchURL('release/add'),
11-
transformMBMatchURL('release/*/edit*'),
12-
],
8+
include: mb`release/${mbid}`,
139
};
1410

1511
export default metadata;
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { transformMBMatchURL } from '@lib/util/metadata';
2+
import { createMBRegex as mb, MBID_REGEX_PART as mbid } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: QoL: Select All Update Recordings',
66
description: 'Add buttons to release editor to select all "Update recordings" checkboxes.',
77
'run-at': 'document-idle',
8-
match: [
9-
'release/*/edit',
10-
'release/*/edit?*',
11-
'release/add*',
12-
].map((path) => transformMBMatchURL(path)),
8+
include: mb`release/(add|${mbid}/edit)`,
139
};
1410

1511
export default metadata;

src/mb_supercharged_caa_edits/meta.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import type { UserscriptMetadata } from '@lib/util/metadata';
2-
import { MB_EDIT_PAGE_PATHS, transformMBMatchURL } from '@lib/util/metadata';
2+
import { MB_EDIT_DISPLAY_PAGE_PATTERNS } from '@lib/util/metadata';
33

44
const metadata: UserscriptMetadata = {
55
name: 'MB: Supercharged Cover Art Edits',
66
description: 'Supercharges reviewing cover art edits. Displays release information on CAA edits. Enables image comparisons on removed and added images.',
77
'run-at': 'document-end',
8-
match: [
9-
...MB_EDIT_PAGE_PATHS,
10-
].map((path) => transformMBMatchURL(path)),
8+
include: MB_EDIT_DISPLAY_PAGE_PATTERNS,
119
require: [
1210
'https://cdn.jsdelivr.net/npm/[email protected]/resemble.min.js',
1311
'https://cdn.jsdelivr.net/npm/[email protected]/min/moment-with-locales.min.js',

0 commit comments

Comments
 (0)