Repository: ROpdebee/mb-userscripts
Pull request #534 (2022-07-28 15:13:15)

fix(ecau): warn when NSFW cover is encountered, skip placeholder
When NSFW images are not enabled in a user's preferences, the main cover art displayed on the VGMDB page is a placeholder. When fetching the images from MB when the user is logged in, this placeholder would be included alongside the "hidden" image (which is parsed from the sidebar).

When the user isn't logged in, the NSFW image may not be displayed at all unless a certain cookie is sent. However, for some reason, sending this cookie in the request is ignored. That should be fixed in the future, so we're warning about that now.

https://community.metabrainz.org/t/ropdebees-userscripts-support-thread/551947/94?u=ropdebee

codecov[bot]: # [Codecov](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) Report
> Merging [#534](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) (dc37155) into [main](https://codecov.io/gh/ROpdebee/mb-userscripts/commit/a5bfdb439ed2bcc631af35b2b03a7f5a3cce2696?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) (a5bfdb4) will **decrease** coverage by `0.22%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main     #534      +/-   ##
==========================================
- Coverage   99.77%   99.54%   -0.23%     
==========================================
  Files          57       57              
  Lines        1308     1311       +3     
  Branches      204      205       +1     
==========================================
  Hits         1305     1305              
- Misses          3        6       +3     
```


| [Impacted Files](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck) | Coverage Δ | |
|---|---|---|
| [...c/mb\_enhanced\_cover\_art\_uploads/providers/vgmdb.ts](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck#diff-c3JjL21iX2VuaGFuY2VkX2NvdmVyX2FydF91cGxvYWRzL3Byb3ZpZGVycy92Z21kYi50cw==) | `100.00% <100.00%> (ø)` | |
| [src/lib/util/array.ts](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck#diff-c3JjL2xpYi91dGlsL2FycmF5LnRz) | `83.33% <0.00%> (-16.67%)` | :arrow_down: |
| [src/mb\_enhanced\_cover\_art\_uploads/fetch.ts](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck#diff-c3JjL21iX2VuaGFuY2VkX2NvdmVyX2FydF91cGxvYWRzL2ZldGNoLnRz) | `100.00% <0.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534?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/534?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ruben+Opdebeeck). Last update [a5bfdb4...dc37155](https://codecov.io/gh/ROpdebee/mb-userscripts/pull/534?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/src/mb_enhanced_cover_art_uploads/providers/vgmdb.ts b/src/mb_enhanced_cover_art_uploads/providers/vgmdb.ts
index 48c26eb1..5fad019f 100644
--- a/src/mb_enhanced_cover_art_uploads/providers/vgmdb.ts
+++ b/src/mb_enhanced_cover_art_uploads/providers/vgmdb.ts
@@ -127,6 +127,7 @@ for (const [key, value] of Object.entries(__CAPTION_TYPE_MAPPING)) {
 }
 
 const PLACEHOLDER_URL = '/db/img/album-nocover-medium.gif';
+const NSFW_PLACEHOLDER_URL = '/db/img/album-nsfw-medium.gif';
 
 function cleanupCaption(captionRest: string): string {
     return captionRest
@@ -182,11 +183,18 @@ export class VGMdbProvider extends CoverArtProvider {
         // Add the main cover if it's not in the gallery
         const mainCoverUrl = qsMaybe<HTMLDivElement>('#coverart', pageDom)?.style.backgroundImage.match(/url\(["']?(.+?)["']?\)/)?.[1];
         if (mainCoverUrl && mainCoverUrl !== PLACEHOLDER_URL && !galleryCovers.some((cover) => urlBasename(cover.url) === urlBasename(mainCoverUrl))) {
-            galleryCovers.unshift({
-                url: new URL(mainCoverUrl, url.origin),
-                types: [ArtworkTypeIDs.Front],
-                comment: '',
-            });
+            if (mainCoverUrl === NSFW_PLACEHOLDER_URL) {
+                // FIXME: We should be able to work around this by sending a cookie.
+                // I've tried, but for some reason either the cookie isn't being sent,
+                // or VGMdb isn't accepting it.
+                LOGGER.warn('Heads up! The main cover of this VGMdb release is marked as NSFW. The original image may have been skipped. Please adjust your VGMdb preferences to show NSFW images to enable fetching these.');
+            } else {
+                galleryCovers.unshift({
+                    url: new URL(mainCoverUrl, url.origin),
+                    types: [ArtworkTypeIDs.Front],
+                    comment: '',
+                });
+            }
         }
 
         return galleryCovers;


Test patch:
diff --git a/tests/test-data/__recordings__/vgmdb-provider_1905514784/extracting-images_1310741912/extracts-covers-for-release-with-NSFW-cover_3684978920.warc b/tests/test-data/__recordings__/vgmdb-provider_1905514784/extracting-images_1310741912/extracts-covers-for-release-with-NSFW-cover_3684978920.warc
new file mode 100644
index 00000000..f2b18bf8
--- /dev/null
+++ b/tests/test-data/__recordings__/vgmdb-provider_1905514784/extracting-images_1310741912/extracts-covers-for-release-with-NSFW-cover_3684978920.warc
@@ -0,0 +1,771 @@
+WARC/1.1
+WARC-Filename: vgmdb provider/extracting images/extracts covers for release with NSFW cover
+WARC-Date: 2022-07-28T15:53:02.839Z
+WARC-Type: warcinfo
+WARC-Record-ID: <urn:uuid:45af004c-dbdc-4db4-84cb-29bfde956981>
+Content-Type: application/warc-fields
+Content-Length: 119
+
+software: warcio.js
+harVersion: 1.2
+harCreator: {"name":"Polly.JS","version":"6.0.5","comment":"persister:fs-warc"}
+
+
+WARC/1.1
+WARC-Concurrent-To: <urn:uuid:f3949381-9a5b-49d5-acfd-13ca2787557b>
+WARC-Target-URI: https://vgmdb.net/album/103079
+WARC-Date: 2022-07-28T15:53:02.841Z
+WARC-Type: request
+WARC-Record-ID: <urn:uuid:4f3c661a-91b5-4f9d-ace6-142f47a278a5>
+Content-Type: application/http; msgtype=request
+WARC-Payload-Digest: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+WARC-Block-Digest: sha256:7a3b293c781554a54b31f6b0b40c5aef0fad8ccebf21088f5539dfa93529c1db
+Content-Length: 30
+
+GET /album/103079 HTTP/1.1
+
+
+
+WARC/1.1
+WARC-Concurrent-To: <urn:uuid:f3949381-9a5b-49d5-acfd-13ca2787557b>
+WARC-Target-URI: https://vgmdb.net/album/103079
+WARC-Date: 2022-07-28T15:53:02.841Z
+WARC-Type: metadata
+WARC-Record-ID: <urn:uuid:ee1e3102-5dd3-4ab1-9529-ad819bc188c3>
+Content-Type: application/warc-fields
+WARC-Payload-Digest: sha256:5759e007c7b8e4b92bb4496638426c0734fbebc143a59cac3e31a7a8aa712d8c
+WARC-Block-Digest: sha256:5759e007c7b8e4b92bb4496638426c0734fbebc143a59cac3e31a7a8aa712d8c
+Content-Length: 539
+
+harEntryId: 3db97df82fc37c062e00adc876601e10
+harEntryOrder: 0
+cache: {}
+startedDateTime: 2022-07-28T15:53:02.176Z
+time: 587
+timings: {"blocked":-1,"dns":-1,"connect":-1,"send":0,"wait":587,"receive":0,"ssl":-1}
+warcRequestHeadersSize: 49
+warcRequestCookies: []
+warcResponseHeadersSize: 795
+warcResponseCookies: [{"name":"vgmlastvisit","value":"1659023582","expires":"2023-07-28T15:53:02.000Z","maxAge":31536000,"path":"/","domain":".vgmdb.net","secure, vgmlastactivity":"0","secure, vgm_filter_ver":"1"}]
+responseDecoded: false
+
+
+WARC/1.1
+WARC-Target-URI: https://vgmdb.net/album/103079
+WARC-Date: 2022-07-28T15:53:02.840Z
+WARC-Type: response
+WARC-Record-ID: <urn:uuid:f3949381-9a5b-49d5-acfd-13ca2787557b>
+Content-Type: application/http; msgtype=response
+WARC-Payload-Digest: sha256:27823bcacddd5905ef2bc15530b47928f64a1684b665083cfc166dc2b7efe73b
+WARC-Block-Digest: sha256:80666013e90b93d4a2e37b91ccdc399dbd718e67f13ec7d67c8e2354ad71619e
+Content-Length: 32802
+
+HTTP/1.1 200 OK
+cache-control: private
+connection: close
+content-encoding: gzip
+content-type: text/html; charset=UTF-8
+date: Thu, 28 Jul 2022 15:53:02 GMT
+pragma: private
+referrer-policy: no-referrer-when-downgrade
+server: nginx
+set-cookie: vgmlastvisit=1659023582; expires=Fri, 28-Jul-2023 15:53:02 GMT; Max-Age=31536000; path=/; domain=.vgmdb.net; secure, vgmlastactivity=0; expires=Fri, 28-Jul-2023 15:53:02 GMT; Max-Age=31536000; path=/; domain=.vgmdb.net; secure, vgm_filter_ver=1; path=/, vgm_filter_pubtype=7; path=/, vgm_filter_distype=511; path=/, vgm_filter_category_on=0; path=/, vgm_filter_category_off=0; path=/
+transfer-encoding: chunked
+x-content-type-options: nosniff
+x-frame-options: SAMEORIGIN
+x-xss-protection: 1; mode=block
+x-pollyjs-finalurl: https://vgmdb.net/album/103079
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html dir="ltr" lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time | PURPLE056-SOP - VGMdb</title>
+
+
+
+
+
+<link href="https://vgmdb.net/album/103079" rel="canonical" />
+
+
+<meta name="keywords" content="PURPLE056-SOP, SEISHUN FRAGILE / 青春フラジャイル, PC, album, ost, soundtrack, tracklist, scans, covers, vgm, translation" />
+<meta name="description" content="Commercial, Retailer Bonus (CD) published by Purple software on Aug 28, 2020 containing drama from SEISHUN FRAGILE" />
+<meta property="og:title" content="PURPLE056-SOP | SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time - VGMdb" />
+<meta property="og:type" content="website" />
+
+<meta property="og:url" content="https://vgmdb.net/album/103079" />
+<meta name="twitter:card" content="summary" />
+<meta name="twitter:site" content="@vgmdb" />
+<meta name="twitter:title" content="PURPLE056-SOP | SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time - VGMdb" />
+<meta name="twitter:description" content="Commercial, Retailer Bonus (CD) published by Purple software on Aug 28, 2020 containing drama from SEISHUN FRAGILE" />
+
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="generator" content="VGMdb" />
+
+
+<!-- CSS Stylesheet -->
+<style type="text/css" id="vbulletin_css">
+/**
+* vBulletin 3.8.11 CSS
+* Style: 'Default Style'; Style ID: 1
+*/
+@import url("/forums/clientscript/vbulletin_css/style-5593b98d-00001.css");
+</style>
+<link rel="stylesheet" type="text/css" href="/forums/clientscript/vbulletin_important.css?v=3811" />
+
+
+<link rel="stylesheet" type="text/css" href="/db/vgmdb.css?20220131" />
+<link rel="stylesheet" type="text/css" href="/db/css/vgmdb-colorcode-title.css?20190227" id="colorcode" />
+<link rel="stylesheet" type="text/css" href="/db/jquery.autocomplete.css?20091023" />
+<link rel="stylesheet" type="text/css" href="/db/jquery.jcarousel.css?20091124" />
+<link rel="stylesheet" type="text/css" href="/db/highslide.css?080623" />
+<!-- / CSS Stylesheet -->
+
+<script type="text/javascript" src="/db/clientscript/yahoo-dom-event.js"></script>
+<script type="text/javascript" src="/db/clientscript/connection-min.js"></script>
+<script type="text/javascript">
+<!--
+var SESSIONURL = "s=73ace54c135515a43554771a54168a87&";
+var SECURITYTOKEN = "guest";
+var IMGDIR_MISC = "/db/images/misc";
+var vb_disable_ajax = parseInt("1", 10);
+// -->
+</script>
+<script type="text/javascript" src="/forums/clientscript/vbulletin_global.js?v=3811"></script>
+<script type="text/javascript" src="/forums/clientscript/vbulletin_menu.js?v=3811"></script>
+<link rel="alternate" type="application/rss+xml" title="VGMdb Forums RSS Feed" href="/forums/external.php?type=RSS2" />
+
+<script type="text/javascript" src="/db/clientscript/jquery-1.4.min.js"></script>
+<script type="text/javascript" src="/db/clientscript/jquery.compressed.js"></script>
+<script type="text/javascript" src="/db/clientscript/jquery.tristate.js?20100420"></script>
+<script type="text/javascript" src="/db/clientscript/highslide.packed.js?080620"></script>
+<script type="text/javascript" src="/db/clientscript/vgmdb_global.js?220525"></script>
+<link rel="search" type="application/opensearchdescription+xml" title="Search VGMdb" href="/db/search.xml" />
+<link rel="icon" href="/favicon.ico" type="image/vnd.microsoft.icon" />
+<link rel="shortcut icon" href="/favicon.ico" type="image/vnd.microsoft.icon" />
+<script language="javascript" type="text/javascript">
+$(document).ready(function() {
+	var ItemType = new Array;
+	ItemType["0"] = "Album";
+	ItemType["1"] = "Artist";
+	ItemType["2"] = "Organization";
+	hs.showCredits = false;
+	hs.allowMultipleInstances = false;
+	hs.graphicsDir = '/db/highslide/graphics/';
+	function formatItem(row) {
+		return "<span style='float: right; margin-left: 10px' class='tinyfont label'>" + ItemType[row[3]] + " #" + row[1] + "</span>" + row[0];
+	}
+	$('#navoptions a').click(function() {
+		if (!$('#pref_content form').length) {
+			$.ajax({
+				url: '/db/user.php?do=preferences',
+				beforeSend: function() {
+					$('#navoptions').css('visibility', 'hidden').parent('li').css('background', 'transparent url(/db/img/ajax_loader_small.gif) center center no-repeat');
+				},
+				success: function(data) { 
+					$('#navoptions').css('visibility', 'visible').parent('li').css('background', 'transparent url(/db/img/vgmdbsubnav2010.gif) -593px 0 no-repeat');
+					$('#pref_content').html(data.html);
+					$('#pref_content form label.tristate').tristate();
+					$('#pref_content form').ajaxForm({
+						beforeSubmit: function() {
+							$('#pref_content form input[type=submit]').css('visibility', 'hidden').parent('div').css('background', 'transparent url(/db/img/ajax_loader_small.gif) center center no-repeat');
+						},
+						success: function() {
+							$('#pref').slideUp('fast');
+							$('#pref_content form input[type=submit]').css('visibility', 'visible').parent('div').css('background', 'none');
+							$('#navoptions a').blur();
+						}
+					});
+					$('#pref').slideDown('fast');
+				},
+				dataType: 'json'
+			});
+		}
+		else {
+			if ($('#pref').is(':visible')) {
+				$('#pref').slideUp('fast');
+				$('#navoptions a').blur();
+			}
+			else $('#pref').slideDown('fast');
+		}
+		return false;
+	});
+	$("#simplesearch").autocomplete('/db/ajax-autocomplete.php', {
+		minChars: 3,
+		delay: 1000,
+		max: 150,
+		width: 500,
+		scrollHeight: 600,
+		selectFirst: false,
+		formatItem: formatItem
+	}).result(function(event, item) {
+		location.href = item[2];
+	});
+	$('label.tristate').tristate(); // 'sup IRA
+	
+});</script>
+<meta name="google-site-verification" content="3hoyGArPHzn4HMMeNfYCjhqM5Ci_675U7M7NxbiLJ1A" />
+<script type="text/javascript">
+
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-4758350-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script');
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    ga.setAttribute('async', 'true');
+    document.documentElement.firstChild.appendChild(ga);
+  })();
+
+</script>
+<style>
+.alt1_dark {
+    background: #151F30;
+    color: #FFFFFF;
+}
+
+.alt2_dark {
+    background: #252B3F;
+    color: #FFFFFF;
+}
+span.link_doc { display: block; background: transparent url('/db/icons/album-cover.gif') 0 2px no-repeat; padding-left: 14px; margin-bottom: 4px; }
+</style>
+<!---->
+
+
+<style>tr.extracred { display: none; }</style>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function() {
+	$("input.button").click(function() { window.clickedButton = $(this); });
+	$("form").submit(function (e) { if (window.clickedButton != null && !window.clickedButton.hasClass("warnbutton")) { $("input.button:not(.warnbutton)").click(function() { return false; }); } });
+	$(".auto-collapse").each(function() {
+		if ($(this).height() >= 42) {
+			$(this).css('cursor', 'pointer').css('overflow', 'hidden');
+			if (!$(this).hasClass("auto-collapse-yellow")) {
+				$(this).children(":first").css('mask-image', 'linear-gradient(to bottom, black 20px, transparent 50px)');
+				$(this).children(":first").css('-webkit-mask-image', 'linear-gradient(to bottom, black 20px, transparent 50px)');
+			}
+			$(this).click(function(e) {
+				$(this).css('max-height', 'none').css('cursor', 'auto');
+				if (!$(this).hasClass("auto-collapse-yellow")) {
+					$(this).children(":first").css('mask-image', '').css('-webkit-mask-image', '');
+				}
+			});
+		}
+	});
+	$('textarea.resizable:not(.processed), select.resizable:not(.processed), div.resizable:not(.processed)').TextAreaResizer();
+	
+	
+	$('#tlnav li a').click(function() {
+		$('#tlnav li').removeClass('active');
+		$(this).parent('li').addClass('active');
+		$('span.tl').hide();
+		$('#' + $(this).attr('rel')).show();
+		return false;
+	});
+	
+	
+	
+	$('table.role tr.rolebit').mouseover(function() { $(this).addClass("over"); });
+	$('table.role tr.rolebit').mouseout(function() { $(this).removeClass("over"); });
+	
+	
+	
+	
+	$(document).ready(function() {
+		$('.collapsible_section').click(function() {
+			var src = $(this).find('img').attr('src');
+			if (src.indexOf('close') > 0) {
+				$(this).find('img').attr('src', src.replace('close', 'open'));
+				$('#' + $(this).attr('rel')).hide('fast');
+			} else {
+				$(this).find('img').attr('src', src.replace('open', 'close'));
+				$('#' + $(this).attr('rel')).show('fast');
+			}
+			return false;
+		});
+	});
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	// shamelessly ripped from Digg
+	var cheatCode = '';
+	var maxCode = 40;
+	$(document).keydown(function(key) {
+		if (cheatCode.length < maxCode) {
+			var k = (key.keyCode == 0) ? key.charCode : key.keyCode;
+			cheatCode = cheatCode + String(k) + ' ';
+			switch (cheatCode) {
+				case '38 40 37 39 65 13 ':
+				window.location='/album/2072';
+				break;
+				case '38 38 40 40 37 39 37 39 66 65 13 ':
+				window.location='/album/3778';
+				break;
+				case '73 68 68 81 68 ':
+				window.location='/album/2950';
+				break;
+			}
+		}
+	});
+});
+</script>
+</head>
+<body style="padding: 0; margin: 0">
+<a name="top"></a>
+<div class="page" style="background-color: #1B273D; height: 100px; width: 100%;">
+<div style="float: right; margin-top: 10px; margin-right: 10px;">
+	<ul class="pipelist tinyfont">
+	
+	<li class="smallfont first-child"><span id="navlogin"><a href="#">Login</a><script type="text/javascript"> vBmenu.register('navlogin'); </script></span></li>
+	<li class="smallfont"><a title="Register a new account" href="/forums/register.php">Register</a></li>
+	
+	</ul>
+</div>
+<div style="white-space: nowrap;">
+<!-- logo -->
+<div style="height: 100px; float: left;"><a href="/"><img src="/db/img/vgmdblogo.png" alt="VGMdb" style="padding: 10px; width: 250px; height: 80px; border: 0" /></a></div>
+<!-- /logo -->
+<!-- top nav -->
+<div style="height: 100px; float: left; position: relative; margin-left: 1px;">
+<ul id="topnav">
+	<li id="nav_album"><a title="Official Albums, Enclosures, Doujins" href="/db/albums.php">Albums</a><a class="buttonSubmit" href="/album/new" title="Submit a new album"><img src="/db/img/button-add-big.png" alt="" /></a></li>
+	<li id="nav_artist"><a title="Composers, Arrangers, Lyricists, Performers" href="/db/artists.php">Artists</a><a class="buttonSubmit" href="/db/artists-submit.php" title="Submit a new artist"><img src="/db/img/button-add-big.png" alt="" /></a></li>
+	<!-- <li id="nav_track"><a title="Instrumentals, Vocals, Sound Effects, Voice Dramas" href="#">Tracks</a></li> -->
+	<li id="nav_label"><a title="Music Labels, Publishers, Organizations and Groups" href="/db/org.php">Organizations</a><a class="buttonSubmit" href="/db/org-submit.php" title="Submit a new publisher"><img src="/db/img/button-add-big.png" alt="" /></a></li>
+	<li id="nav_product"><a title="Games, Video, Radio/Drama Programs, Print Publications" href="/db/product.php">Products</a><a class="buttonSubmit" href="/db/product-submit.php" title="Submit a new product"><img src="/db/img/button-add-big.png" alt="" /></a></li>
+	<li id="nav_event"><a title="Conventions, Gatherings and Shows" href="/db/events.php">Events</a><a class="buttonSubmit" href="/db/event-submit.php" title="Submit a new event"><img src="/db/img/button-add-big.png" alt="" /></a></li>
+	
+	<!--li id="nav_podcast"><a title="VGM Decibel, our bi-monthly podcast" href="/cast">Podcast</a></li-->
+</ul>
+</div>
+<!-- / top nav -->
+</div>
+</div>
+<div class="label" style="clear: both; width: 100%; background-color: #2F364F; font-family: Arial">
+<ul id="subnav">
+	<li id="nav_search" style="width: 250px">
+		<form name="navsearch" action="/search" method="get">
+			<div>
+                 <input type="text" class="bginput smallfont ac_input ac_default" name="q" id="simplesearch" maxlength="150" style="width: 160px;" enterkeyhint="go" />
+                 <select name="type" style="width: 70px;" >
+                    <option value="" >all</option>
+                    <option value="album" >albums</option>
+                    <option value="artist" >artists</option>
+                    <option value="org" >organizations</option>
+                    <option value="product" >products</option>
+                </select>
+            </div>
+		</form>
+	</li>
+	<li id="nav_advsearch"><a title="More search options" href="/search">Advanced Search</a></li>
+	<li id="nav_update"><a title="Latest submissions and edits" href="/db/recent.php">Updates</a></li>
+	<li id="nav_calendar"><a title="Release schedules" href="/db/calendar.php?year=2022&month=7">Calendar</a></li>
+	<li id="nav_forum"><a title="Community discussions" href="/forums/">Forums</a></li>
+	<li id="nav_market"><a title="Trade with other members" href="/db/marketplace.php?do=view">Marketplace</a></li>
+	<!--li id="nav_users"><a title="User collections" href="/db/collection.php">Users</a></li-->
+	<li id="nav_chat"><a title="Real-time chat" rel="nofollow" href="https://discord.gg/VXgKQUa" target="vgmdbchat">Chat</a></li>
+	
+	<li id="nav_submit"><a title="Submit an album" href="/album/new">Submit Album</a></li>
+	<li id="nav_customize"><span id="navoptions"><a title="Edit your preferences" href="#">Customize</a></span></li>
+</ul>
+</div>
+
+
+	<!-- login form -->
+	<div class="vbmenu_popup" id="navlogin_menu" style="display:none;">
+	<table cellpadding="4" cellspacing="1" border="0"><tr><td style="background: #BBC7CE;">
+	<form action="/forums/login.php?do=login" method="post" onsubmit="md5hash(vb_login_password, vb_login_md5password, vb_login_md5password_utf, 0)">
+	<script type="text/javascript" src="/forums/clientscript/vbulletin_md5.js?v=3811"></script>
+	<table cellpadding="0" cellspacing="3" border="0">
+	<tr>
+		<td class="smallfont"><label for="navbar_username">User Name</label></td>
+		<td><input type="text" class="bginput" style="font-size: 11px" name="vb_login_username" id="navbar_username" size="10" accesskey="u" tabindex="101" value="User Name" onfocus="if (this.value == 'User Name') this.value = '';" /></td>
+		<td class="smallfont" colspan="2" nowrap="nowrap"><label for="cb_cookieuser_navbar"><input type="checkbox" name="cookieuser" value="1" tabindex="103" id="cb_cookieuser_navbar" accesskey="c" />Remember</label></td>
+	</tr><tr>
+		<td class="smallfont"><label for="navbar_password">Password</label></td>
+		<td><input type="password" class="bginput" style="font-size: 11px" name="vb_login_password" id="navbar_password" size="10" tabindex="102" /></td>
+		<td><input type="submit" class="button" value="Log in" tabindex="104" title="Enter your username and password in the boxes provided to login, or click the 'register' button to create a profile for yourself." accesskey="s" /></td>
+	</tr>
+	</table>
+	<input type="hidden" name="s" value="73ace54c135515a43554771a54168a87" />
+	<input type="hidden" name="securitytoken" value="guest" />
+	<input type="hidden" name="do" value="login" />		
+	<input type="hidden" name="vb_login_md5password" />
+	<input type="hidden" name="vb_login_md5password_utf" />
+	</form>
+	</td></tr></table>
+	</div>
+	<!-- / login form -->
+
+
+<!-- content table -->
+<div class="page" style="padding:20px 20px 0 20px">
+
+<div id="pref" style="width: 100%; background-color:#1B273D; margin-bottom: 20px; display: none">
+	<b class="rtop"><b></b></b>
+	<div id="pref_content"></div>
+	<b class="rbot"><b></b></b>
+</div>
+
+
+
+<!-- main page contents -->
+<table width="100%" cellpadding="0" cellspacing="0" border="0" align="left"><tr><td width="100%" style="background-color: #1B273D;" valign="top">
+	<b class="rtop"><b></b></b>
+
+
+	<div id="innermain" style="padding: 6px 10px 0px 10px">
+		<span style="float:right;" class="label smallfont"><a href="/db/albums-discuss.php?id=103079">Discuss</a> | <span id="albumtools"><a href="#">Edit</a><script type="text/javascript"> vBmenu.register('albumtools'); </script></span></span>
+
+		<h1><span class="albumtitle" lang="en" style="display:inline">SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time</span><span class="albumtitle" lang="ja" style="display:none"><em> / </em>『青春フラジャイル』ソフマップドラマCD『温泉ファンタイム』</span><span class="albumtitle" lang="ja-Latn" style="display:none"><em> / </em>SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time</span> </h1>
+
+		<div style="padding-left: 10px; padding-right: 10px; padding-bottom: 6px; font-size: 9pt; color: #788990;"><span class="albumtitle" lang="en" style="display:inline">『青春フラジャイル』ソフマップドラマCD『温泉ファンタイム』<br /></span><span class="albumtitle" lang="ja" style="display:none">SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time<br /></span><span class="albumtitle" lang="ja-Latn" style="display:none">SEISHUN FRAGILE Sofmap Drama CD: Onsen Fun Time<br />『青春フラジャイル』ソフマップドラマCD『温泉ファンタイム』<br /></span></div>
+		<div style="padding-left: 10px; padding-right: 10px; margin-top: 10px;"><div id="leftfloat" style="float: left; width: 250px; height: 250px; padding-top: 4px; padding-bottom: 4px;">
+<div style="width: 250px; height: 250px; overflow: hidden">
+<table cellpadding="0" cellspacing="0" border="0" align="left" width="250">
+<tr><td align="center" valign="middle" style="height: 250px; width:250px">
+<div id="coverart" style="background-image: url('/db/img/album-nsfw-medium.gif')" title="PURPLE056-SOP"></div>
+</td></tr></table></div></div>
+
+<div id="rightfloat" style="margin-left: 270px;">
+<div style="background-color: #2F364F;">
+<b class="rtop"><b></b></b>
+
+<div style="max-height:300px; overflow:auto;">
+<table id="album_infobit_large" cellpadding="1" cellspacing="1">
+<tr><td nowrap="nowrap"><span class="label"><b>Catalog Number</b></span></td>
+<td width="100%">PURPLE056-SOP 
+
+
+</td></tr>
+
+
+
+<tr><td nowrap="nowrap"><span class="label"><b>Release Date</b></span></td>
+<td><a title="View albums released on Aug 28, 2020" href="/db/calendar.php?year=2020&month=8#20200828">Aug 28, 2020</a> </td></tr>
+
+<tr><td nowrap="nowrap"><span class="label"><b>Publish Format</b></span></td>
+<td>Commercial, Retailer Bonus  </td></tr>
+
+<tr><td nowrap="nowrap"><span class="label"><b>Release Price</b></span></td>
+<td>Not for Sale (Japan) </td></tr>
+
+<tr><td nowrap="nowrap"><span class="label"><b>Media Format</b></span></td>
+<td>CD</td></tr>
+
+<tr><td nowrap="nowrap"><span class="label"><b>Classification</b></span></td>
+<td>Drama </td></tr>
+
+
+    <tr class="maincred"><td nowrap="nowrap"><span class="label"><b>Publisher</b></span></td><td><a href="/org/1226"><span class="productname" lang="en" style="display:inline">Purple software</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja" style="display:none">Purple software</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja-Latn" style="display:none">Purple software</span></a></td></tr><tr class="maincred"><td nowrap="nowrap"><span class="label"><b>Exclusive Retailer</b></span></td><td><a href="/org/752"><span class="productname" lang="en" style="display:inline">Sofmap</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja" style="display:none">株式会社ソフマップ</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja-Latn" style="display:none">Sofmap</span></a></td></tr>
+
+
+
+
+
+</table>
+</div>
+
+<div style="clear: left; line-height: 0; height: 0; overflow: hidden; visibility: hidden"></div>
+<b class="rbot"><b></b></b>
+</div></div>
+
+
+
+
+
+
+
+</div>
+		<br style="clear: both" />
+
+
+
+<div style="padding-left: 10px; padding-right: 10px"><h3><span style="float:left">Credits <a href="#" class="collapsible_section" rel="collapse_credits"><img src="/db/img/collapse_close.png" /></a></span></h3><span style="clear:both;display:block;"></span>
+<div style="background-color: #2F364F;" id="collapse_credits">
+<b class="rtop"><b></b></b>
+<div style="max-height:1000px; padding: 6px 10px 10px 6px; overflow:auto;">
+<table id="album_infobit_large" style="height:auto" cellpadding="1" cellspacing="1">
+<tbody>
+<tr class="maincred"><td nowrap="nowrap"><span class="label"><b><span title="Performer" class="artistname" lang="en" style="display:inline">Performer</span><span style="display:none"><em> / </em></span><span title="Performer" class="artistname" lang="ja" style="display:none">Performer</span></b></span></td><td width="100%"><a href="/artist/34792"><span title="東シヅ" class="artistname" lang="en" style="display:inline">Shidu Aduma</span><span style="display:none"><em> / </em></span><span title="Shidu Aduma" class="artistname" lang="ja" style="display:none">東シヅ</span></a>, <a href="/artist/31551"><span title="秋野花" class="artistname" lang="en" style="display:inline">Hana Akino</span><span style="display:none"><em> / </em></span><span title="Hana Akino" class="artistname" lang="ja" style="display:none">秋野花</span></a>, <a href="/artist/30949"><span title="小鳥居夕花" class="artistname" lang="en" style="display:inline">Yuka Kotorii</span><span style="display:none"><em> / </em></span><span title="Yuka Kotorii" class="artistname" lang="ja" style="display:none">小鳥居夕花</span></a>, <a href="/artist/30947"><span title="小波すず" class="artistname" lang="en" style="display:inline">Suzu Sazanami</span><span style="display:none"><em> / </em></span><span title="Suzu Sazanami" class="artistname" lang="ja" style="display:none">小波すず</span></a></td></tr>
+</tbody>
+</table>
+</div>
+<b class="rbot"><b></b></b>
+</div></div><br/>
+
+		<div style="padding-left: 10px; padding-right: 10px">
+		
+			<div><h3 style="float: left">Tracklist <a href="#" class="collapsible_section" rel="tracklist"><img src="/db/img/collapse_close.png" /></a></h3>
+			<ul id="tlnav" class="tabnav" style="margin-left: 10px"><li class="active"><a class='smallfont' rel='tl138816' href='#'>Romaji</a></li><li><a class='smallfont' rel='tl137795' href='#'>Japanese</a></li></ul>
+			</div>
+
+			<div style="background-color: #2F364F; clear: both">
+			<b class="rtop"><b></b></b>
+			<div style="padding: 6px 10px 10px 10px" id="tracklist"><span class="tl" id="tl138816">
+	<!-- / tracklist tools menu -->
+<span style="font-size:8pt"><b>Disc 1</b></span>
+<br /><br />
+<table cellpadding="1" cellspacing="0" border="0" class="role">
+<tr class="rolebit">
+<td style="border-bottom: 1px solid #3C405C" class="smallfont"><span class="label">01</span></td>
+<td style="border-bottom: 1px solid #3C405C; padding-left: 6px" class="smallfont" width="100%" colspan="2">
+
+Onsen Fun Time</td>
+
+<td style="border-bottom: 1px solid #3C405C; padding-left: 6px" class="smallfont" align="right" nowrap="nowrap"><span class="time">16:09</span>
+
+</td>
+</tr>
+</table>
+<span style="float: right; margin: 1px;">
+  <span class="smallfont" style="color: #606978">Disc length</span>
+  <span class="time">16:09</span>
+</span>
+<br style="clear: both" />
+<h4 style="font-weight: normal; clear:both"><span class="label">
+
+&nbsp;</span>
+
+</h4></span>
+<span class="tl" id="tl137795" style="display: none">
+	<!-- / tracklist tools menu -->
+<span style="font-size:8pt"><b>Disc 1</b></span>
+<br /><br />
+<table cellpadding="1" cellspacing="0" border="0" class="role">
+<tr class="rolebit">
+<td style="border-bottom: 1px solid #3C405C" class="smallfont"><span class="label">01</span></td>
+<td style="border-bottom: 1px solid #3C405C; padding-left: 6px" class="smallfont" width="100%" colspan="2">
+
+温泉ファンタイム</td>
+
+<td style="border-bottom: 1px solid #3C405C; padding-left: 6px" class="smallfont" align="right" nowrap="nowrap"><span class="time">16:09</span>
+
+</td>
+</tr>
+</table>
+<span style="float: right; margin: 1px;">
+  <span class="smallfont" style="color: #606978">Disc length</span>
+  <span class="time">16:09</span>
+</span>
+<br style="clear: both" />
+<h4 style="font-weight: normal; clear:both"><span class="label">
+
+&nbsp;</span>
+
+</h4></span>
+</div>
+			<b class="rbot"><b></b></b>
+			</div>
+
+		</div>
+
+<div style="padding: 20px 10px 10px 10px">
+<h3>Notes  <a href="#" class="collapsible_section" rel="collapse_notes"><img src="/db/img/collapse_close.png" /></a></h3>
+<div style="background-color: #2F364F;" id="collapse_notes">
+<b class="rtop"><b></b></b>
+<div style="padding: 6px 10px 10px 10px" class="smallfont" id="notes">CAST<br />鳥羽 せつな: Shidu Aduma<br />リズ・メイサース: Hana Akino<br />桜宮 氷緒: Yuka Kotorii<br />卯月 透音: Suzu Sazanami<br /><br /><br />Bonus for buying SEISHUN FRAGILE First Press Edition (JAN: 4580108790639) from Sofmap.</div>
+<b class="rbot"><b></b></b>
+</div>
+</div>
+
+	</div>
+
+</td>
+<td id="rightcolumn" rowspan="2" style="width: 270px; padding-left: 20px" valign="top">
+
+<div style="width: 250px; background-color: #1B273D">
+<b class="rtop"><b></b></b>
+<div style="padding: 6px 10px 0px 10px"><h3>Album Stats</h3></div>
+</div>
+<div style="width: 250px; background-color: #2F364F;">
+<div class="smallfont" style="padding: 10px 10px 6px 10px">
+
+
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Contained in</b> 1 collections<br />
+</div>
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Contained in</b> 0 wish lists<br />
+</div>
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Category</b><br />
+Game </div>
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Products represented</b><br />
+<a href="/product/9153"><span class="productname" lang="en" style="display:inline">SEISHUN FRAGILE</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja" style="display:none">青春フラジャイル</span><span style="display:none"><em> / </em></span><span class="productname" lang="ja-Latn" style="display:none">SEISHUN FRAGILE</span></a> </div>
+
+<div><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Platforms represented</b><br />
+PC </div>
+
+<div id="preview"></div>
+
+</div>
+<b class="rbot"><b></b></b>
+</div>
+
+<br style="clear: left" />
+
+
+
+
+
+
+
+<div style="width: 250px; background-color: #1B273D">
+<b class="rtop"><b></b></b>
+<div style="padding: 6px 10px 0px 10px"><h3>Related Albums</h3></div>
+</div>
+<div style="width: 250px; background-color: #2F364F;">
+
+
+<span class="smallfont"><div class="album_infobit_small smallfont label">
+<div class="album_infobit_thumb"><div style="background-image: url('https://thumb-media.vgm.io/albums/92/100529/100529-2165c2c48ada.jpg')">
+<a href="https://vgmdb.net/album/100529" title='SEISHUN FRAGILE OP Theme Song "Seishun Fragile" Rio Asaba Version CD'></a>
+</div></div>
+<ul class="album_infobit_detail">
+<li><a class="albumtitle smallfont album-bonus" href="https://vgmdb.net/album/100529" title='SEISHUN FRAGILE OP Theme Song "Seishun Fragile" Rio Asaba Version CD'><span class="albumtitle" lang="en" style="display:inline">SEISHUN FRAGILE OP Theme Song &quot;Seishun Fragile&quot;...</span><span class="albumtitle" lang="ja" style="display:none"><em> / </em>青春フラジャイル OP主題歌「青春フラジャイル」浅...</span><span class="albumtitle" lang="ja-Latn" style="display:none"><em> / </em>SEISHUN FRAGILE OP Theme Song &quot;Seishun Fragile&quot;...</span></a></li>
+<li><span class="catalog smallfont album-bonus">PURPLE056-OMP</span></li>
+<li>Aug 28, 2020</li>
+</ul>
+</div><div class="album_infobit_small smallfont label">
+<div class="album_infobit_thumb"><div style="background-image: url('https://thumb-media.vgm.io/albums/03/100530/100530-e72afac61c35.jpg')">
+<a href="https://vgmdb.net/album/100530" title='SEISHUN FRAGILE ORIGINAL SOUNDTRACK'></a>
+</div></div>
+<ul class="album_infobit_detail">
+<li><a class="albumtitle smallfont album-bonus" href="https://vgmdb.net/album/100530" title='SEISHUN FRAGILE ORIGINAL SOUNDTRACK'><span class="albumtitle" lang="en" style="display:inline">SEISHUN FRAGILE ORIGINAL SOUNDTRACK</span><span class="albumtitle" lang="ja" style="display:none"><em> / </em>青春フラジャイル オリジナル・サウンドトラック</span><span class="albumtitle" lang="ja-Latn" style="display:none"><em> / </em>SEISHUN FRAGILE ORIGINAL SOUNDTRACK</span></a></li>
+<li><span class="catalog smallfont album-bonus">PURPLE-056OST1~2</span></li>
+<li>Aug 28, 2020</li>
+</ul>
+</div></span>
+<br />
+
+<b class="rbot"><b></b></b>
+</div>
+
+<br style="clear: left" />
+
+<div style="width: 250px; background-color: #2F364F;">
+<b class="rtop"><b></b></b>
+
+<div class="smallfont" style="padding: 6px 10px 6px 10px">
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Added</b><br />
+Aug 28, 2020 <span class="time">09:46 AM</span></div>
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" border = "0" /> <b class="label">Edited</b><br />
+Sep 10, 2020 <span class="time">03:23 AM</span></div>
+
+<div style="margin-bottom: 10px;"><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Page traffic</b><br />
+<span class="time">775</span> visitors<br />
+<span class="time" style="word-break:break-all">0</span> freedb<br />
+</div>
+
+<div><img src="/db/img/arrowbit.gif" alt="" /> <b class="label">Page built in</b><br />
+<span class="time">0.01</span> seconds</div>
+</div>
+
+<b class="rbot"><b></b></b>
+</div>
+
+
+
+</td>
+
+</tr>
+<tr>
+<td valign="bottom" style="background-color: #1B273D;">
+<b class="rbot"><b></b></b>
+</td>
+</tr>
+</table>
+
+<!-- album tools menu -->
+<div class="vbmenu_popup" id="albumtools_menu" style="display:none">
+<table cellpadding="4" cellspacing="1" border="0">
+	
+	<tr><td class="vbmenu_option">You must be logged in to edit.</td></tr>
+	
+</table>
+</div>
+<!-- / album tools menu -->
+
+
+<!-- / main page contents -->
+
+</div>
+<!-- /content area table -->
+<div style="clear: both; height: 20px"></div>
+
+<div class="alt1" style="width: 100%">
+<div id="footer">
+<div style="padding: 20px 10px 0 200px">
+
+
+
+	<div style="float: right; text-align: right; font-family: Arial;" class="label">
+		<a href="/about">About Us</a> &bull;
+		<a href="/faq">F.A.Q.</a> &bull;
+		<a href="/forums/sendmessage.php?s=73ace54c135515a43554771a54168a87" rel="nofollow" accesskey="9">Contact Us</a> &bull;
+		<a href="/db/statistics.php" rel="nofollow">Statistics</a> &bull;
+		<a href="/album/random" rel="nofollow">Random Album</a> &bull;
+		<a href="https://vgmdb.net">Home</a>
+
+		<div class="smallfont" style="font-family: Arial; margin-top: 10px">
+		
+		
+		
+		<a href="/forums/archive/index.php">Archive</a> &bull;
+		
+		<a href="/privacy">Privacy Statement</a> &bull;
+		
+		<a href="#top" onclick="self.scrollTo(0, 0); return false;">Top</a>
+		</div>
+
+	<div style="margin-top: 10px"><form action="index.php" method="get">
+	
+	
+	
+
+	</form></div>
+	</div>
+
+	<div class="label">
+		<h3>VGMdb 1.4</h3>
+		<div class="smallfont"><!-- Do not remove this copyright notice -->
+		
+		<!-- Do not remove this copyright notice --></div>
+		<div class="smallfont">Site code and design copyright VGMdb.net</div>
+		<div class="smallfont">Site material is property of their respective owners.</div>
+		<div class="smallfont">All times are GMT -8. The time now is <span class="time">07:53 AM</span>.</div>
+	</div>
+
+
+
+
+
+</div></div></div>
+
+
+<script type="text/javascript">
+<!--
+	// Main vBulletin Javascript Initialization
+	vBulletin_init();
+//-->
+</script>
+</body>
+</html>
+
diff --git a/tests/unit/mb_enhanced_cover_art_uploads/providers/vgmdb.test.ts b/tests/unit/mb_enhanced_cover_art_uploads/providers/vgmdb.test.ts
index 0aa91a0f..310fff83 100644
--- a/tests/unit/mb_enhanced_cover_art_uploads/providers/vgmdb.test.ts
+++ b/tests/unit/mb_enhanced_cover_art_uploads/providers/vgmdb.test.ts
@@ -186,6 +186,13 @@ describe('vgmdb provider', () => {
             url: 'https://vgmdb.net/album/111880',
             numImages: 0,
             expectedImages: [],
+        }, {
+            // FIXME: This should actually be able to extract the NSFW image by
+            // sending a cookie.
+            desc: 'release with NSFW cover',
+            url: 'https://vgmdb.net/album/103079',
+            numImages: 0,
+            expectedImages: [],
         }];
 
         const extractionFailedCases = [{