Repository: ROpdebee/mb-userscripts
Pull request #253 (2021-11-19 11:23:13)

chore(coll work attrs)!: deprecate now-unnecessary userscript
MB offers all of its functionality itself now. We'll push a final update which displays a message to the user, recommending them to uninstall the script. In a few days, we should remove the whole script.

See #246.

codecov[bot]: # [Codecov](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) Report
> Merging [#253](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) (c987a17) into [main](https://codecov.io/gh/ROpdebee/mb-userscripts/commit/36966318bb564d3dc786eff2e97c84418a40ac05?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) (3696631) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253/graphs/tree.svg?width=650&height=150&src=pr&token=CjulzlICM8&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck)](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck)

```diff
@@            Coverage Diff            @@
##              main      #253   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           40        40           
  Lines          886       886           
  Branches       163       163           
=========================================
  Hits           886       886           
```


| [Impacted Files](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) | Coverage Δ | |
|---|---|---|
| [src/lib/logging/logger.ts](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck#diff-c3JjL2xpYi9sb2dnaW5nL2xvZ2dlci50cw==) | `100.00% <0.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck). Last update [3696631...c987a17](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/253?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck).


Patch:
diff --git a/README.md b/README.md
index add98349..ffb4ee07 100644
--- a/README.md
+++ b/README.md
@@ -69,13 +69,6 @@ Validate work attributes on various MB pages. Highlights invalid (red) or ill-fo
 ## Smaller Quality of Life Scripts
 Smaller scripts that offer minor QoL improvements.
 
-### MB: Collapse Work Attributes
-
-Collapses work attributes when there are too many. Workaround for MBS-11535/MBS-11537.
-
-[![Install](https://img.shields.io/badge/install-2021.9.25-informational?style=for-the-badge&logo=github)](mb_collapse_work_attributes.user.js?raw=1)
-[![Source](https://img.shields.io/badge/source-main-lightgrey?style=for-the-badge&logo=github)](mb_collapse_work_attributes.user.js)
-
 ### MB: QoL: Select All Update Recordings
 Add buttons to release editor to select all "Update recordings" checkboxes. Differs from the built-in "Select All" checkboxes in that it doesn't lock the checkboxes to a given state, enabling you to deselect some checkboxes.
 
diff --git a/mb_collapse_work_attributes.user.js b/mb_collapse_work_attributes.user.js
index 583c7e0d..0c712760 100644
--- a/mb_collapse_work_attributes.user.js
+++ b/mb_collapse_work_attributes.user.js
@@ -1,7 +1,7 @@
 // ==UserScript==
 // @name         MB: Collapse Work Attributes
-// @version      2021.9.25
-// @description  Collapses work attributes when there are too many. Workaround for MBS-11535/MBS-11537.
+// @version      2021.11.19
+// @description  *DEPRECATED* Collapses work attributes when there are too many. Workaround for MBS-11535/MBS-11537.
 // @author       ROpdebee
 // @license      MIT; https://opensource.org/licenses/MIT
 // @namespace    https://github.com/ROpdebee/mb-userscripts
@@ -13,110 +13,9 @@
 // @match        *://*.musicbrainz.org/edit/*
 // @match        *://*.musicbrainz.org/*/edits*
 // @match        *://*.musicbrainz.org/collection/*
-// @require      https://code.jquery.com/jquery-3.6.0.min.js
 // @run-at       document-end
 // ==/UserScript==
 
-let $ = this.$ = this.jQuery = jQuery.noConflict(true);
-
-const ATTR_TRANSLATIONS = [
-    'Attributes',
-    'Eigenschaften',
-    'Attributs',
-    'Attributi',
-    'Eigenschappen'];
-
-CUTOFF = 4; // Consistent with performers on artist page
-
-function setAnchorText($anchor, numHidden, currentlyHidden) {
-    if (currentlyHidden) {
-        $anchor
-            .attr('title', 'Show all attributes')
-            .text('(show ' + numHidden + ' more)');
-    } else {
-        $anchor
-            .attr('title', 'Show less attributes')
-            .text('(show less)');
-    }
-}
-
-function createAnchor() {
-    return $('<a>')
-            .attr('role', 'button')
-}
-
-function processTabulatedPage() {
-    document.querySelectorAll('table.tbl').forEach(processTable);
-}
-
-function processTable(table) {
-    let columnIdx = 1 + [...table.querySelectorAll('thead th')]
-        .findIndex(th => ATTR_TRANSLATIONS.includes(th.innerText));
-    let tooLongAttrColumns = $(table).find('td:nth-child(' + columnIdx + ')')
-        .filter((i, col) => col.querySelectorAll('li').length > 4);
-
-    tooLongAttrColumns.each((i, col) => {
-        let $col = $(col);
-        let hideLis = $col.find('li:nth-child(n+' + (CUTOFF + 1) + ')');
-        let $showAllAnchor = createAnchor();
-        let $newLi = $('<li>').addClass('show-all');
-        $newLi.append($showAllAnchor);
-        $col.find('ul').append($newLi);
-
-        let hidden = false;
-
-        $showAllAnchor.click(() => {
-            hideLis.toggle();
-            hidden = !hidden;
-            setAnchorText($showAllAnchor, hideLis.length, hidden);
-        }).trigger('click');
-    });
-}
-
-function processWorkPage() {
-    let tooLongAttrs = $('dl.properties > dd.work-attribute').slice(CUTOFF);
-    let $showAllAnchor = createAnchor();
-    tooLongAttrs.slice(-1).after($showAllAnchor);
-    let hidden = false;
-
-    $showAllAnchor.click(() => {
-        tooLongAttrs.toggle();
-        tooLongAttrs.prev('dt').toggle();
-        hidden = !hidden;
-        setAnchorText($showAllAnchor, tooLongAttrs.length, hidden);
-    }).trigger('click');
-}
-
-function processEditPage() {
-    $('table.details.edit-work, table.details.add-work').each((i, tbl) => {
-        let tooLongAttrs = $(tbl)
-            .find('tr')
-            .filter((i, tr) => {
-                let attrName = tr.querySelector('th').innerText;
-                return attrName.endsWith(' ID:') || attrName === 'PRS tune code:';
-            }).slice(CUTOFF);
-        let $showAllAnchor = createAnchor();
-        let $tr = $('<tr><th></th><td colspan="2"></td></tr>');
-        $tr.find('td').append($showAllAnchor);
-        tooLongAttrs.slice(-1).after($tr);
-        hidden = false;
-
-        $showAllAnchor.click(() => {
-            tooLongAttrs.toggle();
-            hidden = !hidden;
-            setAnchorText($showAllAnchor, tooLongAttrs.length, hidden);
-        }).trigger('click');
-    });
-
-    $('table.details.merge-works').each((i, tbl) => {
-        tbl.querySelectorAll('table.tbl').forEach(processTable);
-    });
-}
-
-if ((location.pathname.startsWith('/artist/') || location.pathname.startsWith('/collection/')) && location.pathname.split('/')[3] !== 'edits') {
-    processTabulatedPage();
-} else if (location.pathname.startsWith('/work/') && location.pathname.split('/')[3] !== 'edits') {
-    processWorkPage();
-} else {
-    processEditPage();
-}
+document.querySelector('#page').insertAdjacentHTML(
+    'beforebegin',
+    '<div class="banner warning-header"><p>"MB: Collapse Work Attributes" is now deprecated since its functionality has been added to MB, and will no longer receive updates. Please uninstall the userscript to remove this message.</p></div>');
diff --git a/src/mb_enhanced_cover_art_uploads/fetch.ts b/src/mb_enhanced_cover_art_uploads/fetch.ts
index b30e85e2..45f7c98d 100644
--- a/src/mb_enhanced_cover_art_uploads/fetch.ts
+++ b/src/mb_enhanced_cover_art_uploads/fetch.ts
@@ -207,7 +207,12 @@ export class ImageFetcher {
                 } else if (uint32view[0] === 0x46445025) {
                     resolve('application/pdf');
                 } else {
-                    reject(new Error(`${fileName} has an unsupported file type`));
+                    const actualMimeType = resp.responseHeaders.match(/content-type:\s*([^;\s]+)/i)?.[1];
+                    if (actualMimeType?.startsWith('text/')) {
+                        reject(new Error('Expected to receive an image, but received text. Perhaps this provider is not supported yet?'));
+                    } else {
+                        reject(new Error(`Expected "${fileName}" to be an image, but received ${actualMimeType ?? 'unknown file type'}.`));
+                    }
                 }
             });
             reader.readAsArrayBuffer(rawFile.slice(0, 4));


Test patch:
diff --git a/tests/mb_enhanced_cover_art_uploads/fetch.test.ts b/tests/mb_enhanced_cover_art_uploads/fetch.test.ts
index 6c591042..1ba10dc5 100644
--- a/tests/mb_enhanced_cover_art_uploads/fetch.test.ts
+++ b/tests/mb_enhanced_cover_art_uploads/fetch.test.ts
@@ -75,14 +75,36 @@ describe('fetching image contents', () => {
             .rejects.toBeInstanceOf(NetworkError);
     });
 
-    it('rejects on invalid file', async () => {
+    it('rejects on text response', async () => {
         mockXhr.mockResolvedValueOnce(createXhrResponse({
             finalUrl: 'https://example.com/broken',
             response: new Blob(['test']),
+            responseHeaders: 'Content-Type: text/html; charset=utf-8',
         }));
 
         await expect(fetcher.fetchImageContents(new URL('https://example.com/broken'), 'test.jpg', {}))
-            .rejects.toThrow('test.jpg has an unsupported file type');
+            .rejects.toThrow('Expected to receive an image, but received text. Perhaps this provider is not supported yet?');
+    });
+
+    it('rejects on invalid image', async () => {
+        mockXhr.mockResolvedValueOnce(createXhrResponse({
+            finalUrl: 'https://example.com/broken',
+            response: new Blob(['test']),
+            responseHeaders: 'Content-Type: application/json',
+        }));
+
+        await expect(fetcher.fetchImageContents(new URL('https://example.com/broken'), 'test.jpg', {}))
+            .rejects.toThrow('Expected "test.jpg" to be an image, but received application/json.');
+    });
+
+    it('rejects on invalid image without content-type header', async () => {
+        mockXhr.mockResolvedValueOnce(createXhrResponse({
+            finalUrl: 'https://example.com/broken',
+            response: new Blob(['test']),
+        }));
+
+        await expect(fetcher.fetchImageContents(new URL('https://example.com/broken'), 'test.jpg', {}))
+            .rejects.toThrow('Expected "test.jpg" to be an image, but received unknown file type.');
     });
 
     it('resolves with fetched image', async () => {