Release v1.3.0: Multi-source downloads, audio analyzer resilience, mobile improvements

Major Features:
- Multi-source download system (Soulseek/Lidarr with fallback)
- Configurable enrichment speed control (1-5x)
- Mobile touch drag support for seek sliders
- iOS PWA media controls (Control Center, Lock Screen)
- Artist name alias resolution via Last.fm
- Circuit breaker pattern for audio analysis

Critical Fixes:
- Audio analyzer stability (non-ASCII, BrokenProcessPool, OOM)
- Discovery system race conditions and import failures
- Radio decade categorization using originalYear
- LastFM API response normalization
- Mood bucket infinite loop prevention

Security:
- Bull Board admin authentication
- Lidarr webhook signature verification
- JWT token expiration and refresh
- Encryption key validation on startup

Closes #2, #6, #9, #13, #21, #26, #31, #34, #35, #37, #40, #43
This commit is contained in:
Your Name
2026-01-06 20:07:33 -06:00
parent 8fe151a0d1
commit cc8d0f6969
242 changed files with 20562 additions and 7725 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "lidify-backend",
"version": "1.0.0",
"version": "1.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lidify-backend",
"version": "1.0.0",
"version": "1.3.0",
"license": "GPL-3.0",
"dependencies": {
"@bull-board/api": "^6.14.2",
@@ -37,6 +37,7 @@
"jsonwebtoken": "^9.0.2",
"music-metadata": "^11.10.0",
"node-cron": "^4.2.1",
"p-limit": "^7.2.0",
"p-queue": "^9.0.0",
"podcast-index-api": "^1.1.10",
"qrcode": "^1.5.4",
@@ -51,6 +52,7 @@
},
"devDependencies": {
"@types/bcrypt": "^5.0.2",
"@types/cors": "^2.8.19",
"@types/express": "^4.17.21",
"@types/express-session": "^1.17.10",
"@types/jsonwebtoken": "^9.0.10",
@@ -105,9 +107,9 @@
}
},
"node_modules/@borewit/text-codec": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.0.tgz",
"integrity": "sha512-X999CKBxGwX8wW+4gFibsbiNdwqmdQEXmUejIWaIqdrHBgS5ARIOOeyiQbHjP9G58xVEPcuvP6VwwH3A0OFTOA==",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz",
"integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==",
"license": "MIT",
"funding": {
"type": "github",
@@ -115,25 +117,25 @@
}
},
"node_modules/@bull-board/api": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/@bull-board/api/-/api-6.15.0.tgz",
"integrity": "sha512-z8qLZ4uv83hZNu+0YnHzhVoWv1grULuYh80FdC2xXLg8M1EwsOZD9cJ5CNpgBFqHb+NVByTmf5FltIvXdOU8tQ==",
"version": "6.16.2",
"resolved": "https://registry.npmjs.org/@bull-board/api/-/api-6.16.2.tgz",
"integrity": "sha512-d3kDf91FeMw/wYp8FOZJjX4hVqZEmomXtYgNRdZc0a5gTR2bmomvpwJtNBinu2lyIRFoX/Rxilz+CZ6xyw3drQ==",
"license": "MIT",
"dependencies": {
"redis-info": "^3.1.0"
},
"peerDependencies": {
"@bull-board/ui": "6.15.0"
"@bull-board/ui": "6.16.2"
}
},
"node_modules/@bull-board/express": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/@bull-board/express/-/express-6.15.0.tgz",
"integrity": "sha512-c/nnxr5evLNgqoSSEvTwPb+6WaTB3PN3Bq2oMTBtwCUJlZr+s1UX7gx0wVIYHjeZyUdYR7fX7hhh2cRLO5vqeg==",
"version": "6.16.2",
"resolved": "https://registry.npmjs.org/@bull-board/express/-/express-6.16.2.tgz",
"integrity": "sha512-RYjWmRpixgoRVJf4/iZuwbst4EML8EnL+S2vyIn6uE0iqCXFBV63oEYJAhoEA7P50IrrktVBOU2/qTdsbih18g==",
"license": "MIT",
"dependencies": {
"@bull-board/api": "6.15.0",
"@bull-board/ui": "6.15.0",
"@bull-board/api": "6.16.2",
"@bull-board/ui": "6.16.2",
"ejs": "^3.1.10",
"express": "^5.2.0"
}
@@ -430,12 +432,12 @@
}
},
"node_modules/@bull-board/ui": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/@bull-board/ui/-/ui-6.15.0.tgz",
"integrity": "sha512-bb/j6VMq2cfPoE/ZiUO7AcYTL0IjtxvKxkYV0zu+i1pc+JEv3ct4BItCII57knJR/YjZKGmdfr079KJFvzXC5A==",
"version": "6.16.2",
"resolved": "https://registry.npmjs.org/@bull-board/ui/-/ui-6.16.2.tgz",
"integrity": "sha512-L8ylgyJqiCrngne9GvX6zqALXnSLhzGBRaPnmO5y7Ev6K9w84EkcfhzcNw4qNH4SJAdcOm3HVf15dBU2Wznbug==",
"license": "MIT",
"dependencies": {
"@bull-board/api": "6.15.0"
"@bull-board/api": "6.16.2"
}
},
"node_modules/@derhuerst/http-basic": {
@@ -454,9 +456,9 @@
}
},
"node_modules/@emnapi/runtime": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
"integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
"integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1497,9 +1499,9 @@
}
},
"node_modules/@ioredis/commands": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz",
"integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz",
"integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==",
"license": "MIT"
},
"node_modules/@jsdevtools/ono": {
@@ -1861,6 +1863,16 @@
"@types/node": "*"
}
},
"node_modules/@types/cors": {
"version": "2.8.19",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/express": {
"version": "4.17.25",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz",
@@ -3018,9 +3030,9 @@
}
},
"node_modules/file-type": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.1.1.tgz",
"integrity": "sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg==",
"version": "21.3.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.0.tgz",
"integrity": "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==",
"license": "MIT",
"dependencies": {
"@tokenizer/inflate": "^0.4.1",
@@ -3604,12 +3616,12 @@
"license": "ISC"
},
"node_modules/ioredis": {
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz",
"integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==",
"version": "5.9.0",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.0.tgz",
"integrity": "sha512-T3VieIilNumOJCXI9SDgo4NnF6sZkd6XcmPi6qWtw4xqbt8nNz/ZVNiIH1L9puMTSHZh1mUWA4xKa2nWPF4NwQ==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "1.4.0",
"@ioredis/commands": "1.5.0",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
@@ -4096,9 +4108,9 @@
}
},
"node_modules/music-metadata": {
"version": "11.10.3",
"resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-11.10.3.tgz",
"integrity": "sha512-j0g/x4cNNZW6I5gdcPAY+GFkJY9WHTpkFDMBJKQLxJQyvSfQbXm57fTE3haGFFuOzCgtsTd4Plwc49Sn9RacDQ==",
"version": "11.10.5",
"resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-11.10.5.tgz",
"integrity": "sha512-G0i86zpL7AARmZx8XEkHBVf7rJMQDFfGEFc1C83//rKHGuaK0gwxmNNeo9mjm4g07KUwoT0s0dW7g5QwZhi+qQ==",
"funding": [
{
"type": "github",
@@ -4111,14 +4123,14 @@
],
"license": "MIT",
"dependencies": {
"@borewit/text-codec": "^0.2.0",
"@borewit/text-codec": "^0.2.1",
"@tokenizer/token": "^0.3.0",
"content-type": "^1.0.5",
"debug": "^4.4.3",
"file-type": "^21.1.1",
"file-type": "^21.2.0",
"media-typer": "^1.1.0",
"strtok3": "^10.3.4",
"token-types": "^6.1.1",
"token-types": "^6.1.2",
"uint8array-extras": "^1.5.0"
},
"engines": {
@@ -4315,15 +4327,15 @@
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.2.0.tgz",
"integrity": "sha512-ATHLtwoTNDloHRFFxFJdHnG6n2WUeFjaR8XQMFdKIv0xkXjrER8/iG9iu265jOM95zXHAfv9oTkqhrfbIzosrQ==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
"yocto-queue": "^1.2.1"
},
"engines": {
"node": ">=6"
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -4341,10 +4353,25 @@
"node": ">=8"
}
},
"node_modules/p-locate/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-queue": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.0.1.tgz",
"integrity": "sha512-RhBdVhSwJb7Ocn3e8ULk4NMwBEuOxe+1zcgphUy9c2e5aR/xbEsdVXxHJ3lynw6Qiqu7OINEyHlZkiblEpaq7w==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz",
"integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^5.0.1",
@@ -4516,9 +4543,9 @@
}
},
"node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@@ -5211,12 +5238,12 @@
}
},
"node_modules/token-types": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.1.tgz",
"integrity": "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz",
"integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==",
"license": "MIT",
"dependencies": {
"@borewit/text-codec": "^0.1.0",
"@borewit/text-codec": "^0.2.1",
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
@@ -5228,16 +5255,6 @@
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/token-types/node_modules/@borewit/text-codec": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.1.1.tgz",
"integrity": "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -5535,6 +5552,18 @@
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz",
"integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==",
"license": "MIT",
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/z-schema": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",