diff --git a/Gulpfile.js b/Gulpfile.js index 51dfd58..a78cc58 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -18,7 +18,7 @@ var uglify = require("gulp-uglify"); var deporder = require("gulp-deporder"); var changed = require("gulp-changed"); var imagemin = require("gulp-imagemin"); -var minifyCss = require("gulp-minify-css"); +var minifyCss = require("gulp-clean-css"); var ghPages = require("gulp-gh-pages"); var babel = require('gulp-babel'); diff --git a/package-lock.json b/package-lock.json index e5b2c06..cfe9b42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,11 +16,11 @@ "gulp-autoprefixer": "^8.0.0", "gulp-babel": "^8.0.0", "gulp-changed": "^3.2.0", + "gulp-clean-css": "^4.3.0", "gulp-concat": "^2.6.1", "gulp-deporder": "^1.2.0", "gulp-gh-pages": "^0.6.0-6", "gulp-imagemin": "^7", - "gulp-minify-css": "^1.2.4", "gulp-rename": "^1.4.0", "gulp-sass": "^5.1.0", "gulp-sourcemaps": "^2.6.5", @@ -54,6 +54,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -1808,15 +1809,6 @@ "node": ">=8" } }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "engines": { - "node": ">=0.4.2" - } - }, "node_modules/ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", @@ -2031,15 +2023,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", @@ -2134,15 +2117,6 @@ "node": ">=8" } }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -2391,15 +2365,6 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "node_modules/beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/bin-build": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", @@ -2975,42 +2940,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/bufferstreams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.0.1.tgz", - "integrity": "sha1-z7GtlWjTujz+k1upq92VLeiKqyo=", - "dev": true, - "dependencies": { - "readable-stream": "^1.0.33" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/bufferstreams/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/bufferstreams/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/bufferstreams/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "node_modules/bytes": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", @@ -3275,34 +3204,6 @@ "node": ">=0.10.0" } }, - "node_modules/clean-css": { - "version": "3.4.28", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", - "integrity": "sha512-aTWyttSdI2mYi07kWqHi24NUU9YlELFKGOAgFzZjDN1064DMAOy2FBuoyGmkKRlXkbpXd0EVHmiVkbKhKoirTw==", - "dev": true, - "dependencies": { - "commander": "2.8.x", - "source-map": "0.4.x" - }, - "bin": { - "cleancss": "bin/cleancss" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -3851,15 +3752,6 @@ "type": "^1.0.1" } }, - "node_modules/dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -4288,39 +4180,6 @@ "node": ">=4" } }, - "node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "node_modules/duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -6482,6 +6341,8 @@ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -6652,6 +6513,52 @@ "xtend": "~4.0.1" } }, + "node_modules/gulp-clean-css": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz", + "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-css": "4.2.3", + "plugin-error": "1.0.1", + "through2": "3.0.1", + "vinyl-sourcemaps-apply": "0.2.1" + } + }, + "node_modules/gulp-clean-css/node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/gulp-clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-clean-css/node_modules/through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "2 || 3" + } + }, "node_modules/gulp-cli": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", @@ -6987,21 +6894,6 @@ "node": ">=8" } }, - "node_modules/gulp-minify-css": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/gulp-minify-css/-/gulp-minify-css-1.2.4.tgz", - "integrity": "sha512-byBqFQM/HrZoUVYihu/03iYH4m7U5TjSGhr6/7JvpMHh9+woewsCtEp6Noif2VXB+idDoM4ECd9sw+St+KFqsg==", - "deprecated": "Please use gulp-clean-css", - "dev": true, - "dependencies": { - "clean-css": "^3.3.3", - "gulp-util": "^3.0.5", - "object-assign": "^4.0.1", - "readable-stream": "^2.0.0", - "vinyl-bufferstream": "^1.0.1", - "vinyl-sourcemaps-apply": "^0.2.0" - } - }, "node_modules/gulp-rename": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", @@ -7106,148 +6998,6 @@ "xtend": "~4.0.1" } }, - "node_modules/gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", - "dev": true, - "dependencies": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/gulp-util/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/gulp-util/node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "node_modules/gulp-util/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gulp-util/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-util/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/gulp-util/node_modules/vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", @@ -8618,60 +8368,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "node_modules/lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "node_modules/lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "node_modules/lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "node_modules/lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -8684,77 +8380,12 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, "node_modules/lodash.isfinite": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "dev": true }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "node_modules/lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, "node_modules/logalot": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", @@ -9496,15 +9127,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "dependencies": { - "duplexer2": "0.0.2" - } - }, "node_modules/mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", @@ -10459,6 +10081,7 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", "dev": true, + "peer": true, "dependencies": { "nanoid": "^3.1.30", "picocolors": "^1.0.0", @@ -13100,15 +12723,6 @@ "node": ">= 0.10" } }, - "node_modules/vinyl-bufferstream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz", - "integrity": "sha1-BTeGn1gO/6TKRay0dXnkuf5jCBo=", - "dev": true, - "dependencies": { - "bufferstreams": "1.0.1" - } - }, "node_modules/vinyl-fs": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", @@ -13395,6 +13009,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, + "peer": true, "requires": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -14645,12 +14260,6 @@ "indent-string": "^4.0.0" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, "ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", @@ -14805,12 +14414,6 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", @@ -14882,12 +14485,6 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -15072,12 +14669,6 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, "bin-build": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", @@ -15554,41 +15145,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "bufferstreams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.0.1.tgz", - "integrity": "sha1-z7GtlWjTujz+k1upq92VLeiKqyo=", - "dev": true, - "requires": { - "readable-stream": "^1.0.33" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, "bytes": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", @@ -15792,27 +15348,6 @@ } } }, - "clean-css": { - "version": "3.4.28", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", - "integrity": "sha512-aTWyttSdI2mYi07kWqHi24NUU9YlELFKGOAgFzZjDN1064DMAOy2FBuoyGmkKRlXkbpXd0EVHmiVkbKhKoirTw==", - "dev": true, - "requires": { - "commander": "2.8.x", - "source-map": "0.4.x" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -16271,12 +15806,6 @@ "type": "^1.0.1" } }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true - }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -16621,41 +16150,6 @@ } } }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -18414,6 +17908,7 @@ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, + "peer": true, "requires": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -18541,6 +18036,44 @@ } } }, + "gulp-clean-css": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz", + "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==", + "dev": true, + "requires": { + "clean-css": "4.2.3", + "plugin-error": "1.0.1", + "through2": "3.0.1", + "vinyl-sourcemaps-apply": "0.2.1" + }, + "dependencies": { + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, "gulp-cli": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", @@ -18817,20 +18350,6 @@ } } }, - "gulp-minify-css": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/gulp-minify-css/-/gulp-minify-css-1.2.4.tgz", - "integrity": "sha512-byBqFQM/HrZoUVYihu/03iYH4m7U5TjSGhr6/7JvpMHh9+woewsCtEp6Noif2VXB+idDoM4ECd9sw+St+KFqsg==", - "dev": true, - "requires": { - "clean-css": "^3.3.3", - "gulp-util": "^3.0.5", - "object-assign": "^4.0.1", - "readable-stream": "^2.0.0", - "vinyl-bufferstream": "^1.0.1", - "vinyl-sourcemaps-apply": "^0.2.0" - } - }, "gulp-rename": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", @@ -18926,119 +18445,6 @@ } } }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, "gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", @@ -20064,60 +19470,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -20130,77 +19482,12 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, "lodash.isfinite": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "dev": true }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, "logalot": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", @@ -20804,15 +20091,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, "mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", @@ -21537,6 +20815,7 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", "dev": true, + "peer": true, "requires": { "nanoid": "^3.1.30", "picocolors": "^1.0.0", @@ -23660,15 +22939,6 @@ "replace-ext": "^1.0.0" } }, - "vinyl-bufferstream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz", - "integrity": "sha1-BTeGn1gO/6TKRay0dXnkuf5jCBo=", - "dev": true, - "requires": { - "bufferstreams": "1.0.1" - } - }, "vinyl-fs": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", diff --git a/package.json b/package.json index 5136f65..8a19b6e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "gulp-deporder": "^1.2.0", "gulp-gh-pages": "^0.6.0-6", "gulp-imagemin": "^7", - "gulp-minify-css": "^1.2.4", + "gulp-clean-css": "^4.3.0", "gulp-rename": "^1.4.0", "gulp-sass": "^5.1.0", "gulp-sourcemaps": "^2.6.5", diff --git a/src/assets/js/api/api.js b/src/assets/js/api/api.js index 2526d91..96e1db3 100644 --- a/src/assets/js/api/api.js +++ b/src/assets/js/api/api.js @@ -1,10 +1,17 @@ /*requires: api/lastfm.js +api/musicbrainz.js */ var api = api || {}; var superCount = 0; +// Queue for artists that need MusicBrainz fallback lookup +var musicbrainzFallbackQueue = []; +var musicbrainzProcessingActive = false; +var musicbrainzProcessedCount = 0; +var musicbrainzFoundCount = 0; + (function (window, document) { let getHardcodedCountries = () => new Promise((res, rej) => d3.json("assets/data/artist-countries.json", (err, data) => @@ -71,8 +78,51 @@ var superCount = 0; }) .map(countryData); - /** - * Tries to find out the country for a specified artist. + /** + * Convert country name to country data + * @param {String} countryName - Country name (e.g., "United States", "Sweden") + * @returns {Object|null} Country data object with id, name, etc., or null if not found + */ + api.convertCountryNameToCountry = function(countryName) { + if (!countryName) return null; + + var countryNameLower = countryName.toLowerCase(); + var countryMatch = cname[countryNameLower]; + + if (countryMatch && countryMatch.length > 0) { + var country = countryMatch[0]; + return { + id: country.id, + name: country.mainName, + country: country.mainName, + tag: country.tag || country.mainName.toLowerCase(), + mainName: country.mainName + }; + } + + // Try to find by matching any of the names array + var country = countryData.find(function(d) { + return d.names.some(function(name) { + return name.toLowerCase() === countryNameLower; + }); + }); + + if (country) { + return { + id: country.id, + name: country.mainName, + country: country.mainName, + tag: country.tag || country.mainName.toLowerCase(), + mainName: country.mainName + }; + } + + console.warn("Unknown country name:", countryName); + return null; + }; + + /** + * Tries to find out the country for a specified artist. * @param {String} artist Name of the artist to get country for * @param {Function} callback Callback function, called when the search is over (whether a country's been found or not) * The callback function takes one argument, this object: @@ -165,6 +215,27 @@ var superCount = 0; console.info("Potentially incorrect country for '" + artist + "': " + bestTag.country + ", using the tag '" + bestTag.tag + "'"); } + // If no country found from Last.fm tags, queue for MusicBrainz fallback + if (!bestTag.id && !bestTag.country) { + // Last.fm succeeded but no country tag found - queue for MusicBrainz fallback + var playcount = STORED_ARTISTS[artist] ? STORED_ARTISTS[artist].playcount : 0; + musicbrainzFallbackQueue.push({ + artist: artist, + url: STORED_ARTISTS[artist] ? STORED_ARTISTS[artist].url : null, + playcount: playcount + }); + + // Sort queue by playcount (highest first) to prioritize artists with most scrobbles + musicbrainzFallbackQueue.sort(function(a, b) { + return (b.playcount || 0) - (a.playcount || 0); + }); + + // Start processing if not already active + if (!musicbrainzProcessingActive) { + api.startMusicBrainzProcessing(); + } + } + callback(Object.assign({ "artist": artist, }, bestTag)); }); } @@ -385,4 +456,198 @@ var superCount = 0; api.lastfm.send("user.getFriends", [["user", SESSION.name]], callback); } + /** + * Get the queue of artists that need MusicBrainz fallback lookup + * @returns {Array} Array of artist objects + */ + api.getMusicBrainzFallbackQueue = function() { + return musicbrainzFallbackQueue; + }; + + /** + * Check if an artist is currently in the MusicBrainz fallback queue + * @param {String} artistName - Name of the artist to check + * @returns {Boolean} True if artist is in queue + */ + api.isArtistInMusicBrainzQueue = function(artistName) { + return musicbrainzFallbackQueue.some(function(item) { + return item.artist === artistName; + }); + }; + + /** + * Queue multiple artists for MusicBrainz fallback lookup + * @param {Array} artists - Array of artist objects with artist, url, playcount properties + */ + api.queueArtistsForMusicBrainz = function(artists) { + if (!artists || !Array.isArray(artists)) { + return; + } + + var queuedCount = 0; + artists.forEach(function(art) { + // Skip if already has a country + if (STORED_ARTISTS[art.artist] && STORED_ARTISTS[art.artist].country && STORED_ARTISTS[art.artist].country.id) { + return; + } + + // Skip if already in queue + if (api.isArtistInMusicBrainzQueue(art.artist)) { + return; + } + + // Add to queue + musicbrainzFallbackQueue.push({ + artist: art.artist, + url: art.url || (STORED_ARTISTS[art.artist] ? STORED_ARTISTS[art.artist].url : null), + playcount: art.playcount || (STORED_ARTISTS[art.artist] ? STORED_ARTISTS[art.artist].playcount : 0) + }); + queuedCount++; + }); + + if (queuedCount > 0) { + // Sort queue by playcount (highest first) + musicbrainzFallbackQueue.sort(function(a, b) { + return (b.playcount || 0) - (a.playcount || 0); + }); + + // Start processing if not already active + if (!musicbrainzProcessingActive) { + api.startMusicBrainzProcessing(); + } + } + }; + + /** + * Clear the MusicBrainz fallback queue + */ + api.clearMusicBrainzFallbackQueue = function() { + musicbrainzFallbackQueue = []; + }; + + /** + * Start processing MusicBrainz fallbacks continuously + * Processes artists as they're added to the queue, prioritizing by scrobbles + */ + api.startMusicBrainzProcessing = function() { + if (musicbrainzProcessingActive) { + return; // Already processing + } + + musicbrainzProcessingActive = true; + musicbrainzProcessedCount = 0; + musicbrainzFoundCount = 0; + + // Process next item in queue + var processNext = function() { + // Sort queue by playcount (highest first) to prioritize artists with most scrobbles + musicbrainzFallbackQueue.sort(function(a, b) { + return (b.playcount || 0) - (a.playcount || 0); + }); + + if (musicbrainzFallbackQueue.length === 0) { + // Queue is empty, stop processing + musicbrainzProcessingActive = false; + return; + } + + // Get next item from queue (highest playcount) + var queueItem = musicbrainzFallbackQueue.shift(); + + var processResult = function(result) { + musicbrainzProcessedCount++; + + if (result.error) { + if (result.error === "rate_limit") { + // Retry after longer delay - put back in queue + musicbrainzFallbackQueue.unshift(queueItem); + setTimeout(function() { + api.musicbrainz.queueRequest(queueItem.artist, processResult); + }, 2000); + return; + } + // Other errors: not_found, no_country, api_error - just skip + // Process next item after delay + setTimeout(processNext, 1100); + return; + } + + if (result.countryName) { + // Convert country name to country data + var countryData = api.convertCountryNameToCountry(result.countryName); + + if (countryData) { + musicbrainzFoundCount++; + + // Update STORED_ARTISTS + STORED_ARTISTS[result.artist] = STORED_ARTISTS[result.artist] || {}; + STORED_ARTISTS[result.artist].country = { + id: countryData.id, + name: countryData.name + }; + + // Remove artist from no-countries list + if (typeof noCountries !== 'undefined' && typeof noCountries.removeArtist === 'function') { + noCountries.removeArtist(result.artist); + } + + // Create artist object for countryCountObj + var artistObj = { + artist: result.artist, + id: countryData.id, + country: countryData.name, + url: queueItem.url || STORED_ARTISTS[result.artist].url || "", + playcount: queueItem.playcount || STORED_ARTISTS[result.artist].playcount || 0 + }; + + // Update countryCountObj (only if SESSION.name is available) + if (typeof SESSION !== 'undefined' && SESSION.name) { + var countryId = countryData.id.toString(); + if (!countryCountObj[countryId]) { countryCountObj[countryId] = {}; } + if (!countryCountObj[countryId][SESSION.name]) { countryCountObj[countryId][SESSION.name] = []; } + var exists = countryCountObj[countryId][SESSION.name].some(function(a) { return a.artist === result.artist; }); + if (!exists) { + countryCountObj[countryId][SESSION.name].push(artistObj); + var newArtistsByCountry = {}; + newArtistsByCountry[countryId] = [artistObj]; + map.addArtists(newArtistsByCountry); + localforage.setItem("artists", STORED_ARTISTS); + window.localStorage.countryCountObj = JSON.stringify(countryCountObj); + } + } + } + } + + // Process next item after delay (respect rate limit) + setTimeout(processNext, 1100); + + // Trigger update of no-countries list to reflect queue changes + // Use setTimeout to avoid calling during render + setTimeout(function() { + if (typeof noCountries !== 'undefined' && typeof noCountries.updateList === 'function') { + noCountries.updateList(); + } + }, 0); + }; + + // Queue the request (MusicBrainz module handles rate limiting) + api.musicbrainz.queueRequest(queueItem.artist, processResult); + }; + + // Start processing + processNext(); + }; + + /** + * Process artists in the MusicBrainz fallback queue + * This is kept for backwards compatibility but now just calls startMusicBrainzProcessing + * @param {Function} progressCallback - Optional callback for progress updates (not used in new implementation) + */ + api.processMusicBrainzFallbacks = function(progressCallback) { + // Just start processing if not already active + if (!musicbrainzProcessingActive) { + api.startMusicBrainzProcessing(); + } + }; + })(window, document); diff --git a/src/assets/js/api/musicbrainz.js b/src/assets/js/api/musicbrainz.js new file mode 100644 index 0000000..bc78038 --- /dev/null +++ b/src/assets/js/api/musicbrainz.js @@ -0,0 +1,241 @@ +var api = api || {}; + +api.musicbrainz = (function() { + var requestQueue = []; + var isProcessing = false; + var lastRequestTime = 0; + var MIN_REQUEST_INTERVAL = 1000; // 1 second minimum between requests + + // Mapping for common subdivisions to countries + var subdivisionToCountry = { + "England": "United Kingdom", + "Scotland": "United Kingdom", + "Wales": "United Kingdom", + "Northern Ireland": "United Kingdom" + }; + + /** + * Extract country name from artist data + * @param {Object} artistData - Artist data from MusicBrainz API + * @returns {Object} Object with countryName and areaName, or null if not found + */ + function extractCountryName(artistData) { + var countryName = null; + var areaName = null; + + // Check area field first + if (artistData.area) { + if (artistData.area.type === "Country" && artistData.area.name) { + countryName = artistData.area.name; + areaName = artistData.area.name; + } else if (artistData.area.type === "Subdivision" && artistData.area.name) { + countryName = subdivisionToCountry[artistData.area.name]; + areaName = artistData.area.name; + } + } + + // Check begin-area if area didn't work + if (!countryName && artistData["begin-area"]) { + if (artistData["begin-area"].type === "Country" && artistData["begin-area"].name) { + countryName = artistData["begin-area"].name; + areaName = artistData["begin-area"].name; + } else if (artistData["begin-area"].type === "Subdivision" && artistData["begin-area"].name) { + countryName = subdivisionToCountry[artistData["begin-area"].name]; + areaName = artistData["begin-area"].name; + } + } + + return countryName ? { countryName: countryName, areaName: areaName } : null; + } + + /** + * Get country for an artist from MusicBrainz API + * @param {String} artist - Artist name + * @param {Function} callback - Callback function with result object + */ + function getCountry(artist, callback) { + var url = "https://musicbrainz.org/ws/2/artist/?query=artist:" + encodeURIComponent(artist) + "&fmt=json&limit=1"; + + // Use XMLHttpRequest for consistency with rest of codebase and better abort support + var xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + // Check for CORS error (status 0 typically indicates CORS failure) + if (xhr.status === 0) { + callback({ + artist: artist, + error: "cors_error" + }); + return; + } + + // Check for rate limit + if (xhr.status === 503) { + callback({ + artist: artist, + error: "rate_limit" + }); + return; + } + + // Check for other HTTP errors + if (xhr.status < 200 || xhr.status >= 300) { + callback({ + artist: artist, + error: "api_error" + }); + return; + } + + // Parse JSON response + var data; + try { + data = JSON.parse(xhr.responseText); + } catch (e) { + callback({ + artist: artist, + error: "parse_error" + }); + return; + } + + // Check if we got valid artist data + if (!data || !data.artists || !data.artists.length) { + callback({ + artist: artist, + error: "not_found" + }); + return; + } + + // Get first artist result + var artistData = data.artists[0]; + + // Extract country name from artist data + var countryInfo = extractCountryName(artistData); + + if (countryInfo) { + callback({ + artist: artist, + countryName: countryInfo.countryName, + area: countryInfo.areaName + }); + } else { + callback({ + artist: artist, + error: "no_country" + }); + } + } + }; + + xhr.onerror = function() { + // Network error or CORS error (only fires if status is still 0) + // onreadystatechange will handle status 0, so this is a fallback + if (xhr.readyState === 4 && xhr.status === 0) { + callback({ + artist: artist, + error: "cors_error" + }); + } + }; + + xhr.ontimeout = function() { + callback({ + artist: artist, + error: "api_error" + }); + }; + + try { + xhr.open("GET", url, true); + xhr.setRequestHeader("Accept", "application/json"); + xhr.timeout = 20000; // 20 second timeout + xhr.send(); + } catch (e) { + callback({ + artist: artist, + error: "api_error" + }); + } + + // Return abort function for compatibility + return { + abort: function() { + if (xhr.readyState !== 4 && xhr.readyState !== 0) { + xhr.abort(); + } + } + }; + } + + /** + * Queue a request with rate limiting + * @param {String} artist - Artist name + * @param {Function} callback - Callback function + */ + function queueRequest(artist, callback) { + requestQueue.push({ + artist: artist, + callback: callback + }); + + processQueue(); + } + + /** + * Process the request queue with rate limiting + */ + function processQueue() { + if (isProcessing) { + return; + } + + if (requestQueue.length === 0) { + return; + } + + isProcessing = true; + + var processNext = function() { + if (requestQueue.length === 0) { + isProcessing = false; + return; + } + + var now = Date.now(); + var timeSinceLastRequest = now - lastRequestTime; + var delay = Math.max(0, MIN_REQUEST_INTERVAL - timeSinceLastRequest); + + setTimeout(function() { + var request = requestQueue.shift(); + lastRequestTime = Date.now(); + + getCountry(request.artist, function(result) { + request.callback(result); + + // Process next request + processNext(); + }); + }, delay); + }; + + processNext(); + } + + /** + * Clear the request queue + */ + function clearQueue() { + requestQueue = []; + isProcessing = false; + } + + return { + getCountry: getCountry, + queueRequest: queueRequest, + clearQueue: clearQueue + }; +})(); + diff --git a/src/assets/js/no-countries.js b/src/assets/js/no-countries.js index 2322256..0badb1f 100644 --- a/src/assets/js/no-countries.js +++ b/src/assets/js/no-countries.js @@ -1,6 +1,7 @@ const noCountries = noCountries || {}; var listOfArtistsWithNoCountry = []; +var updateNoCountriesListInterval = null; var saveToStorage = function (key, object, cb) { localforage.setItem(key, object, cb || function () {}); @@ -13,61 +14,91 @@ function sortArtists(data, method) { return data.sort((a, b) => a.artist.localeCompare(b.artist)); } -var addArtistsWithNoCountry = function (data) { - listOfArtistsWithNoCountry = listOfArtistsWithNoCountry.concat(data); - saveToStorage("no_countries", listOfArtistsWithNoCountry); +// Define updateNoCountriesList outside so it can be called globally +function updateNoCountriesList() { + let artistsState = JSON.parse(localStorage.getItem('noCountryArtistsProgress')) || {}; + const sortedData = sortArtists(listOfArtistsWithNoCountry, noCountryArtistSortMethod); + var noCountriesListEl = d3.select(".no-countries__content ul"); + noCountriesListEl.html(""); + sortedData.forEach(function (_art) { + let artistState = artistsState[_art.artist] || { artistName: _art.artist, checked: false }; + let isInQueue = typeof api !== 'undefined' && api.isArtistInMusicBrainzQueue && api.isArtistInMusicBrainzQueue(_art.artist); + let listItem = noCountriesListEl.append("li"); + listItem.append("input") + .attr("type", "checkbox") + .property("checked", artistState.checked) + .attr("id", _art.artist) + .on("change", handleCheckboxChange); + + // Build label HTML with optional MusicBrainz indicator + let labelHtml = '' + _art.artist + ''; + if (isInQueue) { + labelHtml += '...'; + } + labelHtml += '' + _art.playcount + ' scrobbles'; + + listItem.append("label") + .attr("for", _art.artist) + .html(labelHtml); + if (document.querySelector("#hide-checked")?.checked && artistState.checked) { + listItem.style("display", "none"); + } + }) + d3.select(".no-countries__info").html(listOfArtistsWithNoCountry.length + " artists without a country:"); +} - function handleCheckboxChange() { - let artistName = this.id; - let checked = this.checked; - let artistsState = JSON.parse(localStorage.getItem('noCountryArtistsProgress')) || {}; - artistsState[artistName] = { artistName, checked }; - localStorage.setItem('noCountryArtistsProgress', JSON.stringify(artistsState)); - // If you just checked and the filter is on, remove the artist from the DOM - if (checked && document.querySelector("#hide-checked")?.checked) { - this.parentNode.style.display = 'none'; - let nextCheckbox = this.parentNode.nextElementSibling.querySelector('input'); - if (nextCheckbox) { - nextCheckbox.focus(); - } +function handleCheckboxChange() { + let artistName = this.id; + let checked = this.checked; + let artistsState = JSON.parse(localStorage.getItem('noCountryArtistsProgress')) || {}; + artistsState[artistName] = { artistName, checked }; + localStorage.setItem('noCountryArtistsProgress', JSON.stringify(artistsState)); + // If you just checked and the filter is on, remove the artist from the DOM + if (checked && document.querySelector("#hide-checked")?.checked) { + this.parentNode.style.display = 'none'; + let nextCheckbox = this.parentNode.nextElementSibling.querySelector('input'); + if (nextCheckbox) { + nextCheckbox.focus(); } - // get the label element for the filter checked checkbox - let filterCheckedLabel = document.querySelector("label[for='hide-checked']"); - // Update the label to include the number of checked artists - filterCheckedLabel.innerHTML = `Hide checked artists (${document.querySelectorAll("dialog[open] ul li input[type='checkbox']:checked").length})`; - ga('send', { - hitType: 'event', - eventCategory: 'No countries', - eventAction: 'Check artist as done', - eventLabel: 'test' - }); } + // get the label element for the filter checked checkbox + let filterCheckedLabel = document.querySelector("label[for='hide-checked']"); + // Update the label to include the number of checked artists + filterCheckedLabel.innerHTML = `Hide checked artists (${document.querySelectorAll("dialog[open] ul li input[type='checkbox']:checked").length})`; + ga('send', { + hitType: 'event', + eventCategory: 'No countries', + eventAction: 'Check artist as done', + eventLabel: 'test' + }); +} +var addArtistsWithNoCountry = function (data) { + listOfArtistsWithNoCountry = listOfArtistsWithNoCountry.concat(data); + saveToStorage("no_countries", listOfArtistsWithNoCountry); - - function updateNoCountriesList() { - let artistsState = JSON.parse(localStorage.getItem('noCountryArtistsProgress')) || {}; - const sortedData = sortArtists(listOfArtistsWithNoCountry, noCountryArtistSortMethod); - var noCountriesListEl = d3.select(".no-countries__content ul"); - noCountriesListEl.html(""); - sortedData.forEach(function (_art) { - let artistState = artistsState[_art.artist] || { artistName: _art.artist, checked: false }; - let listItem = noCountriesListEl.append("li"); - listItem.append("input") - .attr("type", "checkbox") - .property("checked", artistState.checked) - .attr("id", _art.artist) - .on("change", handleCheckboxChange); - listItem.append("label") - .attr("for", _art.artist) - .html('' + _art.artist + '' + _art.playcount + ' scrobbles'); - if (document.querySelector("#hide-checked")?.checked && artistState.checked) { - listItem.style("display", "none"); + // Queue artists for MusicBrainz fallback if they haven't been queued yet + if (typeof api !== 'undefined' && typeof api.queueArtistsForMusicBrainz === 'function') { + // Filter out artists that are already in the queue or already have a country + var artistsToQueue = data.filter(function(art) { + // Check if artist already has a country in STORED_ARTISTS + if (typeof STORED_ARTISTS !== 'undefined' && STORED_ARTISTS[art.artist] && STORED_ARTISTS[art.artist].country && STORED_ARTISTS[art.artist].country.id) { + return false; // Already has a country, don't queue + } + // Check if already in queue + if (typeof api !== 'undefined' && api.isArtistInMusicBrainzQueue && api.isArtistInMusicBrainzQueue(art.artist)) { + return false; // Already in queue } - }) - d3.select(".no-countries__info").html(listOfArtistsWithNoCountry.length + " artists without a country:"); + return true; // Should be queued + }); + + if (artistsToQueue.length > 0) { + console.log("[NoCountries] Queueing", artistsToQueue.length, "artists for MusicBrainz fallback"); + api.queueArtistsForMusicBrainz(artistsToQueue); + } } + // Check if the checkbox and label already exist if (!d3.select("#hide-checked").node() && !d3.select("label[for='hide-checked']").node()) { // Add the checkbox next to the filter radios @@ -106,6 +137,18 @@ var addArtistsWithNoCountry = function (data) { updateNoCountriesList("scrobbles"); + // Periodically update the list to show/hide MusicBrainz fetching indicators + if (updateNoCountriesListInterval) { + clearInterval(updateNoCountriesListInterval); + } + updateNoCountriesListInterval = setInterval(function() { + // Only update if dialog is open + var dialog = document.querySelector(".no-countries__content"); + if (dialog && dialog.hasAttribute('open')) { + updateNoCountriesList(); + } + }, 1000); // Update every second + document.querySelector(".no-countries__title").addEventListener("click", function () { const dialog = document.querySelector(".no-countries__content"); dialog.showModal(); @@ -135,6 +178,8 @@ var addArtistsWithNoCountry = function (data) { const dialog = document.querySelector(".no-countries__content"); dialog.close(); document.querySelector(".no-countries__title").focus(); + // Update list when dialog closes to reflect any changes + updateNoCountriesList(); }); const dialog = document.querySelector(".no-countries__content"); dialog.addEventListener("click", function (event) { @@ -150,4 +195,33 @@ var addArtistsWithNoCountry = function (data) { } } -noCountries.addArtistsWithNoCountry = addArtistsWithNoCountry; \ No newline at end of file +var removeArtistWithNoCountry = function(artistName) { + // Remove artist from the list + var index = listOfArtistsWithNoCountry.findIndex(function(art) { + return art.artist === artistName; + }); + + if (index !== -1) { + listOfArtistsWithNoCountry.splice(index, 1); + saveToStorage("no_countries", listOfArtistsWithNoCountry); + console.log("[NoCountries] Removed artist from no-countries list:", artistName); + + // Update the UI if dialog is open + var dialog = document.querySelector(".no-countries__content"); + if (dialog && dialog.hasAttribute('open')) { + updateNoCountriesList(); + } + + // Hide the no-countries section if list is now empty + if (listOfArtistsWithNoCountry.length === 0) { + document.querySelector(".no-countries").classList.add("hidden"); + } + + return true; + } + return false; +}; + +noCountries.addArtistsWithNoCountry = addArtistsWithNoCountry; +noCountries.updateList = updateNoCountriesList; +noCountries.removeArtist = removeArtistWithNoCountry; \ No newline at end of file diff --git a/src/assets/js/script.js b/src/assets/js/script.js index 78d90e2..cc786fc 100644 --- a/src/assets/js/script.js +++ b/src/assets/js/script.js @@ -293,19 +293,37 @@ var countryCountObj = {}; // Fade in loader d3.select(".loader").transition().duration(2000).style("opacity", 1); - d3.select("#loading-text").html("Getting library..."); + var loadingTextEl = d3.select("#loading-text"); + if (!loadingTextEl.empty()) { + loadingTextEl.html("Getting library..."); + } else { + console.warn("[Script] #loading-text element not found when trying to set loading message"); + } // Screen reader status update every 30 seconds setTimeout(function () { - announcer.announce(document.getElementById("loading-text")?.innerText); + var loadingText = document.getElementById("loading-text"); + if (loadingText) { + announcer.announce(loadingText.innerText); + } }, 6000); setTimeout(function () { - if (d3.select("#loading-text")?.html() === "Getting library...") { - d3.select("#loading-text").html("Last.fm is taking
a long time to
respond..."); + var loadingText = d3.select("#loading-text"); + if (loadingText.empty()) { + console.warn("[Script] #loading-text element not found, skipping timeout message"); + return; + } + if (loadingText.html() === "Getting library...") { + loadingText.html("Last.fm is taking
a long time to
respond..."); setTimeout(function () { - if (d3.select("#loading-text").html() === "Last.fm is taking
a long time to
respond...") { - d3.select("#loading-text").html("Maybe last.fm has
gone offline...") + var loadingText2 = d3.select("#loading-text"); + if (loadingText2.empty()) { + console.warn("[Script] #loading-text element not found, skipping timeout message"); + return; + } + if (loadingText2.html() === "Last.fm is taking
a long time to
respond...") { + loadingText2.html("Maybe last.fm has
gone offline...") .style("pointer-events", "all"); } }, 8000); @@ -429,6 +447,15 @@ var countryCountObj = {}; CACHED_USERS[user] = new Date().getTime(); window.localStorage.cached_users = JSON.stringify(CACHED_USERS); window.localStorage.countryCountObj = JSON.stringify(countryCountObj); + + // MusicBrainz processing should already be running in parallel if there were artists without countries + // If queue still has items, ensure processing continues + var fallbackQueue = api.getMusicBrainzFallbackQueue(); + if (fallbackQueue.length > 0) { + console.log("Final check: " + fallbackQueue.length + " artists still in MusicBrainz queue"); + // Processing should already be active, but ensure it continues + api.processMusicBrainzFallbacks(); + } } // // Set theme diff --git a/src/assets/scss/pages/_map.scss b/src/assets/scss/pages/_map.scss index b4a3e27..8286618 100644 --- a/src/assets/scss/pages/_map.scss +++ b/src/assets/scss/pages/_map.scss @@ -286,6 +286,19 @@ div.colorChange { &__secondary { opacity: 0.54; } + + &__fetching { + display: inline-block; + margin-left: 0.3em; + color: var(--textPrimary); + animation: blink 1.4s infinite; + font-weight: bold; + + @keyframes blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0.3; } + } + } } dialog { diff --git a/src/index.html b/src/index.html index e5440bc..84a522a 100644 --- a/src/index.html +++ b/src/index.html @@ -407,9 +407,34 @@

List of countries

} - - - + + + +