feat: Add pino-pretty logging and update SunoApi methods
Introduce pino-pretty for improved logging and update SunoApi methods to incorporate new functionalities for generating custom audios, retrieving audio information, and obtaining credit details. The new pino-pretty logging enhances readability and provides better insights into application behavior. These changes align with the broader goal of enhancing developer experience and maintaining application stability. #N/A
This commit is contained in:
parent
0fcf77df6d
commit
2a309f87a7
@ -18,6 +18,7 @@
|
|||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"next": "14.1.4",
|
"next": "14.1.4",
|
||||||
"pino": "^8.19.0",
|
"pino": "^8.19.0",
|
||||||
|
"pino-pretty": "^11.0.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"user-agents": "^1.1.156"
|
"user-agents": "^1.1.156"
|
||||||
|
@ -14,6 +14,9 @@ dependencies:
|
|||||||
pino:
|
pino:
|
||||||
specifier: ^8.19.0
|
specifier: ^8.19.0
|
||||||
version: 8.19.0
|
version: 8.19.0
|
||||||
|
pino-pretty:
|
||||||
|
specifier: ^11.0.0
|
||||||
|
version: 11.0.0
|
||||||
react:
|
react:
|
||||||
specifier: ^18
|
specifier: ^18
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
@ -763,6 +766,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/colorette@2.0.20:
|
||||||
|
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, tarball: https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/combined-stream@1.0.8:
|
/combined-stream@1.0.8:
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -829,6 +836,10 @@ packages:
|
|||||||
is-data-view: 1.0.1
|
is-data-view: 1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/dateformat@4.6.3:
|
||||||
|
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==, tarball: https://registry.npmmirror.com/dateformat/-/dateformat-4.6.3.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/debug@3.2.7:
|
/debug@3.2.7:
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, tarball: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, tarball: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -929,6 +940,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, tarball: https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz}
|
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, tarball: https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/end-of-stream@1.4.4:
|
||||||
|
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, tarball: https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz}
|
||||||
|
dependencies:
|
||||||
|
once: 1.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/enhanced-resolve@5.16.0:
|
/enhanced-resolve@5.16.0:
|
||||||
resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==, tarball: https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz}
|
resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==, tarball: https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
@ -1349,6 +1366,10 @@ packages:
|
|||||||
engines: {node: '>=0.8.x'}
|
engines: {node: '>=0.8.x'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/fast-copy@3.0.2:
|
||||||
|
resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==, tarball: https://registry.npmmirror.com/fast-copy/-/fast-copy-3.0.2.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fast-deep-equal@3.1.3:
|
/fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz}
|
||||||
dev: true
|
dev: true
|
||||||
@ -1377,6 +1398,10 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/fast-safe-stringify@2.1.1:
|
||||||
|
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==, tarball: https://registry.npmmirror.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fastq@1.17.1:
|
/fastq@1.17.1:
|
||||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==, tarball: https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz}
|
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==, tarball: https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1626,6 +1651,10 @@ packages:
|
|||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/help-me@5.0.0:
|
||||||
|
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==, tarball: https://registry.npmmirror.com/help-me/-/help-me-5.0.0.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ieee754@1.2.1:
|
/ieee754@1.2.1:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, tarball: https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, tarball: https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
@ -1878,6 +1907,11 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/joycon@3.1.1:
|
||||||
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, tarball: https://registry.npmmirror.com/joycon/-/joycon-3.1.1.tgz}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/js-tokens@4.0.0:
|
/js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, tarball: https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, tarball: https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz}
|
||||||
|
|
||||||
@ -2029,7 +2063,6 @@ packages:
|
|||||||
|
|
||||||
/minimist@1.2.8:
|
/minimist@1.2.8:
|
||||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, tarball: https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz}
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, tarball: https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/minipass@7.0.4:
|
/minipass@7.0.4:
|
||||||
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==, tarball: https://registry.npmmirror.com/minipass/-/minipass-7.0.4.tgz}
|
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==, tarball: https://registry.npmmirror.com/minipass/-/minipass-7.0.4.tgz}
|
||||||
@ -2198,7 +2231,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, tarball: https://registry.npmmirror.com/once/-/once-1.4.0.tgz}
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, tarball: https://registry.npmmirror.com/once/-/once-1.4.0.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
dev: true
|
|
||||||
|
|
||||||
/optionator@0.9.3:
|
/optionator@0.9.3:
|
||||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, tarball: https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz}
|
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, tarball: https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz}
|
||||||
@ -2285,6 +2317,26 @@ packages:
|
|||||||
split2: 4.2.0
|
split2: 4.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/pino-pretty@11.0.0:
|
||||||
|
resolution: {integrity: sha512-YFJZqw59mHIY72wBnBs7XhLGG6qpJMa4pEQTRgEPEbjIYbng2LXEZZF1DoyDg9CfejEy8uZCyzpcBXXG0oOCwQ==, tarball: https://registry.npmmirror.com/pino-pretty/-/pino-pretty-11.0.0.tgz}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
colorette: 2.0.20
|
||||||
|
dateformat: 4.6.3
|
||||||
|
fast-copy: 3.0.2
|
||||||
|
fast-safe-stringify: 2.1.1
|
||||||
|
help-me: 5.0.0
|
||||||
|
joycon: 3.1.1
|
||||||
|
minimist: 1.2.8
|
||||||
|
on-exit-leak-free: 2.1.2
|
||||||
|
pino-abstract-transport: 1.1.0
|
||||||
|
pump: 3.0.0
|
||||||
|
readable-stream: 4.5.2
|
||||||
|
secure-json-parse: 2.7.0
|
||||||
|
sonic-boom: 3.8.0
|
||||||
|
strip-json-comments: 3.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/pino-std-serializers@6.2.2:
|
/pino-std-serializers@6.2.2:
|
||||||
resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==, tarball: https://registry.npmmirror.com/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz}
|
resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==, tarball: https://registry.npmmirror.com/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
@ -2421,6 +2473,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, tarball: https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz}
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, tarball: https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/pump@3.0.0:
|
||||||
|
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==, tarball: https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz}
|
||||||
|
dependencies:
|
||||||
|
end-of-stream: 1.4.4
|
||||||
|
once: 1.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/punycode@2.3.1:
|
/punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -2590,6 +2649,10 @@ packages:
|
|||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/secure-json-parse@2.7.0:
|
||||||
|
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==, tarball: https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/semver@6.3.1:
|
/semver@6.3.1:
|
||||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, tarball: https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz}
|
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, tarball: https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -2768,7 +2831,6 @@ packages:
|
|||||||
/strip-json-comments@3.1.1:
|
/strip-json-comments@3.1.1:
|
||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/styled-jsx@5.1.1(react@18.2.0):
|
/styled-jsx@5.1.1(react@18.2.0):
|
||||||
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==, tarball: https://registry.npmmirror.com/styled-jsx/-/styled-jsx-5.1.1.tgz}
|
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==, tarball: https://registry.npmmirror.com/styled-jsx/-/styled-jsx-5.1.1.tgz}
|
||||||
@ -3084,7 +3146,6 @@ packages:
|
|||||||
|
|
||||||
/wrappy@1.0.2:
|
/wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/yallist@4.0.0:
|
/yallist@4.0.0:
|
||||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, tarball: https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz}
|
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, tarball: https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz}
|
||||||
|
@ -5,10 +5,10 @@ export async function GET(req: NextRequest) {
|
|||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
try {
|
try {
|
||||||
// 调用 SunoApi.get_limit 方法获取剩余的信用额度
|
// 调用 SunoApi.get_limit 方法获取剩余的信用额度
|
||||||
const limit = await SunoApi.get_limit();
|
const limit = await SunoApi.get_credits();
|
||||||
|
|
||||||
// 使用 NextResponse 构建成功响应
|
// 使用 NextResponse 构建成功响应
|
||||||
return new NextResponse(JSON.stringify({ limit }), {
|
return new NextResponse(JSON.stringify(limit), {
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import UserAgent from 'user-agents';
|
import UserAgent from 'user-agents';
|
||||||
|
import pino from 'pino';
|
||||||
|
const logger = pino();
|
||||||
|
|
||||||
|
|
||||||
interface AudioInfo {
|
interface AudioInfo {
|
||||||
@ -31,7 +32,9 @@ const sleep = (x: number, y?: number): Promise<void> => {
|
|||||||
const max = Math.max(x, y);
|
const max = Math.max(x, y);
|
||||||
timeout = Math.floor(Math.random() * (max - min + 1) + min) * 1000;
|
timeout = Math.floor(Math.random() * (max - min + 1) + min) * 1000;
|
||||||
}
|
}
|
||||||
console.log(`Sleeping for ${timeout / 1000} seconds`);
|
// console.log(`Sleeping for ${timeout / 1000} seconds`);
|
||||||
|
logger.info(`Sleeping for ${timeout / 1000} seconds`);
|
||||||
|
|
||||||
return new Promise(resolve => setTimeout(resolve, timeout));
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +63,10 @@ class SunoApi {
|
|||||||
if (!sid) {
|
if (!sid) {
|
||||||
throw new Error("Failed to get session id");
|
throw new Error("Failed to get session id");
|
||||||
}
|
}
|
||||||
console.log(`Successfully retrieved session ID: ${sid}`);
|
|
||||||
SunoApi.sid = sid; // 保存会话ID以备后用
|
SunoApi.sid = sid; // 保存会话ID以备后用
|
||||||
|
|
||||||
// 使用会话ID获取JWT令牌
|
// 使用会话ID获取JWT令牌
|
||||||
const exchangeTokenUrl = exchangeTokenUrlTemplate.replace('{sid}', sid);
|
const exchangeTokenUrl = exchangeTokenUrlTemplate.replace('{sid}', sid);
|
||||||
// console.log("Exchange Token URL:\n", exchangeTokenUrl);
|
|
||||||
// console.log("Exchange User-Agent:\n", SunoApi.userAgent);
|
|
||||||
// console.log("Exchange Cookie:\n", SunoApi.cookie);
|
|
||||||
const tokenResponse = await axios.post(
|
const tokenResponse = await axios.post(
|
||||||
exchangeTokenUrl,
|
exchangeTokenUrl,
|
||||||
{},
|
{},
|
||||||
@ -78,8 +77,6 @@ class SunoApi {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
console.log("Token Response:\n", JSON.stringify(tokenResponse.data, null, 2));
|
|
||||||
|
|
||||||
return tokenResponse.data.jwt;
|
return tokenResponse.data.jwt;
|
||||||
}
|
}
|
||||||
public static async KeepAlive(): Promise<void> {
|
public static async KeepAlive(): Promise<void> {
|
||||||
@ -99,7 +96,7 @@ class SunoApi {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
console.log("Renew Response:\n", JSON.stringify(renewResponse.data, null, 2));
|
logger.info("KeepAlive...\n");
|
||||||
await sleep(1, 2);
|
await sleep(1, 2);
|
||||||
const newToken = renewResponse.data.jwt;
|
const newToken = renewResponse.data.jwt;
|
||||||
// 更新请求头中的Authorization字段,使用新的JWT令牌
|
// 更新请求头中的Authorization字段,使用新的JWT令牌
|
||||||
@ -111,12 +108,24 @@ class SunoApi {
|
|||||||
make_instrumental: boolean = false,
|
make_instrumental: boolean = false,
|
||||||
wait_audio: boolean = false,
|
wait_audio: boolean = false,
|
||||||
): Promise<AudioInfo[]> {
|
): Promise<AudioInfo[]> {
|
||||||
|
const startTime = Date.now();
|
||||||
const audios = this.generateSongs(prompt, false, undefined, undefined, make_instrumental, wait_audio);
|
const audios = this.generateSongs(prompt, false, undefined, undefined, make_instrumental, wait_audio);
|
||||||
console.log("Custom Generate Response:\n", JSON.stringify(audios, null, 2));
|
const costTime = Date.now() - startTime;
|
||||||
|
logger.info("Generate Response:\n", JSON.stringify(audios, null, 2));
|
||||||
|
logger.info("Cost time: ", costTime);
|
||||||
return audios;
|
return audios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates custom audio based on provided parameters.
|
||||||
|
*
|
||||||
|
* @param prompt The text prompt to generate audio from.
|
||||||
|
* @param tags Tags to categorize the generated audio.
|
||||||
|
* @param title The title for the generated audio.
|
||||||
|
* @param make_instrumental Indicates if the generated audio should be instrumental.
|
||||||
|
* @param wait_audio Indicates if the method should wait for the audio file to be fully generated before returning.
|
||||||
|
* @returns A promise that resolves to an array of AudioInfo objects representing the generated audios.
|
||||||
|
*/
|
||||||
public static async custom_generate(
|
public static async custom_generate(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
tags: string,
|
tags: string,
|
||||||
@ -124,12 +133,25 @@ class SunoApi {
|
|||||||
make_instrumental: boolean = false,
|
make_instrumental: boolean = false,
|
||||||
wait_audio: boolean = false,
|
wait_audio: boolean = false,
|
||||||
): Promise<AudioInfo[]> {
|
): Promise<AudioInfo[]> {
|
||||||
|
const startTime = Date.now();
|
||||||
const audios = await this.generateSongs(prompt, true, tags, title, make_instrumental, wait_audio);
|
const audios = await this.generateSongs(prompt, true, tags, title, make_instrumental, wait_audio);
|
||||||
console.log("Custom Generate Response:\n", JSON.stringify(audios, null, 2));
|
const costTime = Date.now() - startTime;
|
||||||
|
logger.info("Custom Generate Response:\n", JSON.stringify(audios, null, 2));
|
||||||
|
logger.info("Cost time: ", costTime);
|
||||||
return audios;
|
return audios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates songs based on the provided parameters.
|
||||||
|
*
|
||||||
|
* @param prompt The text prompt to generate songs from.
|
||||||
|
* @param isCustom Indicates if the generation should consider custom parameters like tags and title.
|
||||||
|
* @param tags Optional tags to categorize the song, used only if isCustom is true.
|
||||||
|
* @param title Optional title for the song, used only if isCustom is true.
|
||||||
|
* @param make_instrumental Indicates if the generated song should be instrumental.
|
||||||
|
* @param wait_audio Indicates if the method should wait for the audio file to be fully generated before returning.
|
||||||
|
* @returns A promise that resolves to an array of AudioInfo objects representing the generated songs.
|
||||||
|
*/
|
||||||
private static async generateSongs(
|
private static async generateSongs(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
isCustom: boolean,
|
isCustom: boolean,
|
||||||
@ -151,7 +173,7 @@ class SunoApi {
|
|||||||
} else {
|
} else {
|
||||||
payload.gpt_description_prompt = prompt;
|
payload.gpt_description_prompt = prompt;
|
||||||
}
|
}
|
||||||
console.log("generateSongs payload:\n", {
|
logger.info("generateSongs payload:\n", {
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
isCustom: isCustom,
|
isCustom: isCustom,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -171,7 +193,7 @@ class SunoApi {
|
|||||||
timeout: 10000, // 10 seconds timeout
|
timeout: 10000, // 10 seconds timeout
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
console.log("generateSongs Response:\n", JSON.stringify(response.data, null, 2));
|
logger.info("generateSongs Response:\n", JSON.stringify(response.data, null, 2));
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error("Error response:" + response.statusText);
|
throw new Error("Error response:" + response.statusText);
|
||||||
}
|
}
|
||||||
@ -180,10 +202,9 @@ class SunoApi {
|
|||||||
if (wait_audio === true) {
|
if (wait_audio === true) {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
let lastResponse: AudioInfo[] = [];
|
let lastResponse: AudioInfo[] = [];
|
||||||
await sleep(2, 4);
|
await sleep(5, 5);
|
||||||
while (Date.now() - startTime < 30000) {
|
while (Date.now() - startTime < 100000) {
|
||||||
const response = await SunoApi.get(songIds);
|
const response = await SunoApi.get(songIds);
|
||||||
console.log("Waiting for audio Response:\n", JSON.stringify(response, null, 2));
|
|
||||||
const allCompleted = response.every(
|
const allCompleted = response.every(
|
||||||
audio => audio.status === 'streaming' || audio.status === 'complete'
|
audio => audio.status === 'streaming' || audio.status === 'complete'
|
||||||
);
|
);
|
||||||
@ -191,7 +212,7 @@ class SunoApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
lastResponse = response;
|
lastResponse = response;
|
||||||
await sleep(2, 4);
|
await sleep(3, 6);
|
||||||
this.KeepAlive();
|
this.KeepAlive();
|
||||||
}
|
}
|
||||||
return lastResponse;
|
return lastResponse;
|
||||||
@ -216,32 +237,38 @@ class SunoApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 将音频元数据中的歌词(prompt)处理成易于阅读的格式。
|
* Processes the lyrics (prompt) from the audio metadata into a more readable format.
|
||||||
* @param prompt 原始歌词文本。
|
* @param prompt The original lyrics text.
|
||||||
* @returns 处理后的歌词文本。
|
* @returns The processed lyrics text.
|
||||||
*/
|
*/
|
||||||
private static parseLyrics(prompt: string): string {
|
private static parseLyrics(prompt: string): string {
|
||||||
// 假设原始歌词是以特定分隔符(例如,换行符)分隔的,我们可以将其转换为更易于阅读的格式。
|
// Assuming the original lyrics are separated by a specific delimiter (e.g., newline), we can convert it into a more readable format.
|
||||||
// 这里的实现可以根据实际的歌词格式进行调整。
|
// The implementation here can be adjusted according to the actual lyrics format.
|
||||||
// 例如,如果歌词是以连续的文本形式存在,可能需要根据特定的标记(如句号、逗号等)来分割。
|
// For example, if the lyrics exist as continuous text, it might be necessary to split them based on specific markers (such as periods, commas, etc.).
|
||||||
// 下面的实现假设歌词已经是以换行符分隔的。
|
// The following implementation assumes that the lyrics are already separated by newlines.
|
||||||
|
|
||||||
// 使用换行符分割歌词,并确保移除空行。
|
// Split the lyrics using newline and ensure to remove empty lines.
|
||||||
const lines = prompt.split('\n').filter(line => line.trim() !== '');
|
const lines = prompt.split('\n').filter(line => line.trim() !== '');
|
||||||
|
|
||||||
// 将处理后的歌词行重新组合成一个字符串,每行之间用换行符分隔。
|
// Reassemble the processed lyrics lines into a single string, separated by newlines between each line.
|
||||||
// 可以在这里添加额外的格式化逻辑,如添加特定的标记或者处理特殊的行。
|
// Additional formatting logic can be added here, such as adding specific markers or handling special lines.
|
||||||
const formattedLyrics = lines.join('\n');
|
const formattedLyrics = lines.join('\n');
|
||||||
|
|
||||||
return formattedLyrics;
|
return formattedLyrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves audio information for the given song IDs.
|
||||||
|
* @param songIds An optional array of song IDs to retrieve information for.
|
||||||
|
* @returns A promise that resolves to an array of AudioInfo objects.
|
||||||
|
*/
|
||||||
public static async get(songIds?: string[]): Promise<AudioInfo[]> {
|
public static async get(songIds?: string[]): Promise<AudioInfo[]> {
|
||||||
const authToken = await this.getAuthToken();
|
const authToken = await this.getAuthToken();
|
||||||
let url = `${SunoApi.baseUrl}/api/feed/`;
|
let url = `${SunoApi.baseUrl}/api/feed/`;
|
||||||
if (songIds) {
|
if (songIds) {
|
||||||
url = `${url}?ids=${songIds.join(',')}`;
|
url = `${url}?ids=${songIds.join(',')}`;
|
||||||
}
|
}
|
||||||
console.log("Get URL:\n", url);
|
logger.info("Get audio status: ", url);
|
||||||
const response = await axios.get(url, {
|
const response = await axios.get(url, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${authToken}`,
|
'Authorization': `Bearer ${authToken}`,
|
||||||
@ -251,7 +278,6 @@ class SunoApi {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const audios = response.data;
|
const audios = response.data;
|
||||||
console.log("Get Response:\n", JSON.stringify(audios, null, 2));
|
|
||||||
return audios.map((audio: any) => ({
|
return audios.map((audio: any) => ({
|
||||||
id: audio.id,
|
id: audio.id,
|
||||||
title: audio.title,
|
title: audio.title,
|
||||||
@ -270,7 +296,7 @@ class SunoApi {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async get_limit(): Promise<number> {
|
public static async get_credits(): Promise<object> {
|
||||||
const authToken = await this.getAuthToken();
|
const authToken = await this.getAuthToken();
|
||||||
const response = await axios.get(`${SunoApi.baseUrl}/api/billing/info/`, {
|
const response = await axios.get(`${SunoApi.baseUrl}/api/billing/info/`, {
|
||||||
headers: {
|
headers: {
|
||||||
@ -278,7 +304,12 @@ class SunoApi {
|
|||||||
'User-Agent': SunoApi.userAgent,
|
'User-Agent': SunoApi.userAgent,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return response.data.total_credits_left;
|
return {
|
||||||
|
credits_left: response.data.total_credits_left,
|
||||||
|
period: response.data.period,
|
||||||
|
monthly_limit: response.data.monthly_limit,
|
||||||
|
monthly_usage: response.data.monthly_usage,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user