diff --git a/.gitignore b/.gitignore
index c6bba59..a9e3938 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+### Node ###
# Logs
logs
*.log
@@ -89,7 +90,6 @@ out
# Nuxt.js build / generate output
.nuxt
-dist
# Gatsby files
.cache/
@@ -102,7 +102,6 @@ dist
# vuepress v2.x temp and cache directory
.temp
-.cache
# Docusaurus cache and generated files
.docusaurus
@@ -128,3 +127,14 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+
+### Node Patch ###
+# Serverless Webpack directories
+.webpack/
+
+# Optional stylelint cache
+
+# SvelteKit build / generate output
+.svelte-kit
+
+# End of https://www.toptal.com/developers/gitignore/api/node
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cc8fa3e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+# Excel's Neptune Projects
+
+This repository a repository containing my Neptune (TIDAL Modded Client) projects.
+
+## Index:
+- [Copy Lyrics](#copy-lyrics)
+- [ShadowX Theme](#spicetifys-shadowx-port-full-black-theme)
+
+
+### Copy Lyrics
+A plugin that allows the user copy the lyrics only selecting it.
+```
+https://raw.githubusercontent.com/ItzzExcel/neptune-projects/refs/heads/main/plugins/plugins/copy-lyrics/dist/
+```
+
+
+### Spicetify's ShadowX Port (Full-black theme)
+```
+https://raw.githubusercontent.com/ItzzExcel/neptune-projects/refs/heads/main/themes/black-neptune-theme.css
+```
+
\ No newline at end of file
diff --git a/plugins/.gitignore b/plugins/.gitignore
deleted file mode 100644
index 0c50fd5..0000000
--- a/plugins/.gitignore
+++ /dev/null
@@ -1,142 +0,0 @@
-### Node ###
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-.pnpm-debug.log*
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variable files
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-out
-
-# Nuxt.js build / generate output
-.nuxt
-dist
-
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-.temp
-
-# Docusaurus cache and generated files
-.docusaurus
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
-# yarn v2
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
-
-### Node Patch ###
-# Serverless Webpack directories
-.webpack/
-
-# Optional stylelint cache
-
-# SvelteKit build / generate output
-.svelte-kit
-
-# End of https://www.toptal.com/developers/gitignore/api/node
-dist/
\ No newline at end of file
diff --git a/plugins/build.js b/plugins/build.js
index 5203610..ab9ce41 100644
--- a/plugins/build.js
+++ b/plugins/build.js
@@ -3,103 +3,102 @@ const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
-const nativeExternals = ["@neptune", "@plugin", "electron"]
+const nativeExternals = ["@plugin", "electron", "@neptune-types", "@neptune"];
const plugins = fs.readdirSync("./plugins");
for (const plugin of plugins) {
- let pluginPath = path.join("./plugins/", plugin);
+ let pluginPath = path.join("./plugins/", plugin);
- const pluginManifest = JSON.parse(
- fs.readFileSync(path.join(pluginPath, "plugin.json"))
- );
+ const pluginManifest = JSON.parse(
+ fs.readFileSync(path.join(pluginPath, "plugin.json"))
+ );
- const outfile = path.join(pluginPath, "dist/index.js");
+ const outfile = path.join(pluginPath, "dist/index.js");
- esbuild
- .build({
- entryPoints: [
- "./" + path.join(pluginPath, pluginManifest.main ?? "index.js"),
- ],
- plugins: [
- {
- name: "neptuneNativeImports",
- setup(build) {
- build.onLoad(
- { filter: /.*[\/\\].+\.native\.[a-z]+/g },
- async (args) => {
- const result = await esbuild.build({
- entryPoints: [args.path],
- bundle: true,
- minify: true,
- platform: "node",
- format: "iife",
- globalName: "neptuneExports",
- write: false,
- external: nativeExternals
- });
+ esbuild
+ .build({
+ entryPoints: [
+ "./" + path.join(pluginPath, pluginManifest.main ?? "index.js"),
+ ],
+ logLevel: "debug",
+ plugins: [
+ {
+ name: "neptuneNativeImports",
+ setup(build) {
+ build.onLoad(
+ { filter: /.*[\/\\].+\.native\.[a-z]+/g },
+ async (args) => {
+ const result = await esbuild.build({
+ entryPoints: [args.path],
+ bundle: true,
+ minify: true,
+ platform: "node",
+ format: "iife",
+ globalName: "neptuneExports",
+ write: false,
+ external: nativeExternals
+ });
- const outputCode = result.outputFiles[0].text;
+ const outputCode = result.outputFiles[0].text;
- // HATE! WHY WHY WHY WHY WHY (globalName breaks metafile. crying emoji)
- const { metafile } = await esbuild.build({
- entryPoints: [args.path],
- platform: "node",
- write: false,
- metafile: true,
- bundle: true, // I find it annoying that I have to enable bundling.
- format: "esm", // This avoids exports not being properly defined, thus you do not need to change log levels.
- external: nativeExternals,
- });
+ // HATE! WHY WHY WHY WHY WHY (globalName breaks metafile. crying emoji)
+ const { metafile } = await esbuild.build({
+ entryPoints: [args.path],
+ platform: "node",
+ write: false,
+ metafile: true,
+ bundle: true, // I find it annoying that I have to enable bundling.
+ format: "esm", // This avoids exports not being properly defined, thus you do not need to change log levels.
+ external: nativeExternals,
+ });
- const builtExports = Object.values(metafile.outputs)[0].exports;
+ const builtExports = Object.values(metafile.outputs)[0].exports;
- return {
- contents: `import {addUnloadable} from "@plugin";const contextId=NeptuneNative.createEvalScope(${JSON.stringify(
- outputCode
- )});${builtExports
- .map(
- (e) =>
- `export ${
- e == "default" ? "default " : `const ${e} =`
- } NeptuneNative.getNativeValue(contextId,${JSON.stringify(
- e
- )})`
- )
- .join(
- ";"
- )};addUnloadable(() => NeptuneNative.deleteEvalScope(contextId))`,
- };
- }
- );
- },
- },
- ],
- bundle: true,
- minify: true,
- format: "esm",
- external: [
- "@neptune",
- "@plugin",
- ],
- platform: "browser",
- outfile,
- })
- .then(() => {
- fs.createReadStream(outfile)
- // It being md5 does not matter, this is for caching and not security
- .pipe(crypto.createHash("md5").setEncoding("hex"))
- .on("finish", function () {
- fs.writeFileSync(
- path.join(pluginPath, "dist/manifest.json"),
- JSON.stringify({
- name: pluginManifest.name,
- description: pluginManifest.description,
- author: pluginManifest.author,
- hash: this.read(),
- })
- );
+ return {
+ contents: `import {addUnloadable} from "@plugin";const contextId=NeptuneNative.createEvalScope(${JSON.stringify(
+ outputCode
+ )});${builtExports
+ .map(
+ (e) =>
+ `export ${e == "default" ? "default " : `const ${e} =`
+ } NeptuneNative.getNativeValue(contextId,${JSON.stringify(
+ e
+ )})`
+ )
+ .join(
+ ";"
+ )};addUnloadable(() => NeptuneNative.deleteEvalScope(contextId))`,
+ };
+ }
+ );
+ },
+ },
+ ],
+ bundle: true,
+ minify: true,
+ format: "esm",
+ external: nativeExternals,
+ platform: "browser",
+ outfile,
+ metafile: true, // Add this line to generate a metafile
+ })
+ .then((result) => {
+ fs.createReadStream(outfile)
+ // It being md5 does not matter, this is for caching and not security
+ .pipe(crypto.createHash("md5").setEncoding("hex"))
+ .on("finish", function () {
+ fs.writeFileSync(
+ path.join(pluginPath, "dist/manifest.json"),
+ JSON.stringify({
+ name: pluginManifest.name,
+ description: pluginManifest.description,
+ author: pluginManifest.author,
+ hash: this.read(),
+ metafile: result.metafile, // Add this line to include the metafile in the manifest
+ })
+ );
- console.log("Built " + pluginManifest.name + "!");
- });
- });
-}
+ console.log("Built " + pluginManifest.name + "!");
+ });
+ });
+}
\ No newline at end of file
diff --git a/plugins/package-lock.json b/plugins/package-lock.json
index 6d8d051..11a1b74 100644
--- a/plugins/package-lock.json
+++ b/plugins/package-lock.json
@@ -6,18 +6,17 @@
"": {
"name": "neptune-plugin-template",
"dependencies": {
- "react-hot-toast": "^2.5.1"
+ "canvas-confetti": "^1.9.3",
+ "neptune-types": "^1.0.1"
},
"devDependencies": {
- "esbuild": "^0.18.13",
- "neptune-types": "^1.0.0"
+ "esbuild": "^0.18.13"
}
},
"node_modules/@babel/runtime": {
- "version": "7.26.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz",
- "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==",
- "dev": true,
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
+ "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
@@ -400,11 +399,15 @@
"node": ">=12"
}
},
- "node_modules/csstype": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "license": "MIT"
+ "node_modules/canvas-confetti": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz",
+ "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==",
+ "license": "ISC",
+ "funding": {
+ "type": "donate",
+ "url": "https://www.paypal.me/kirilvatev"
+ }
},
"node_modules/esbuild": {
"version": "0.18.20",
@@ -444,41 +447,28 @@
"@esbuild/win32-x64": "0.18.20"
}
},
- "node_modules/goober": {
- "version": "2.1.16",
- "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
- "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
- "license": "MIT",
- "peerDependencies": {
- "csstype": "^3.0.10"
- }
- },
"node_modules/htm": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz",
"integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==",
- "dev": true,
"license": "Apache-2.0"
},
"node_modules/idb-keyval": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==",
- "dev": true,
"license": "Apache-2.0"
},
"node_modules/immutable": {
"version": "5.0.0-beta.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.0-beta.4.tgz",
"integrity": "sha512-sl9RE3lqd2LoQSESc8VV0k8qE9y57iT7dinq3Q+8mR2dqReHDZlgUrudzmFfZhDXBLXlNJMVWv3SG1YpQIokig==",
- "dev": true,
"license": "MIT"
},
"node_modules/neptune-types": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/neptune-types/-/neptune-types-1.0.1.tgz",
"integrity": "sha512-XDkESq/jNTH9La//peJQirzJTwJySxkc4pCjHz1RtgcmoFbYIZ72JR0mkFYNsCZ0oyI7gLgaApd405VzU1gqOw==",
- "dev": true,
"license": "MS-PL",
"dependencies": {
"idb-keyval": "^6.2.1",
@@ -493,54 +483,12 @@
"node_modules/oby": {
"version": "14.3.5",
"resolved": "https://registry.npmjs.org/oby/-/oby-14.3.5.tgz",
- "integrity": "sha512-0RgL6n1qmxdkUgvXFnmG/J+Lv8HWjwnWmULtu/omMxRUV9KhD/8x3sL7DmanUvEOi5wX4xTbef1sKe5NzqGm7g==",
- "dev": true
- },
- "node_modules/react": {
- "version": "19.0.0",
- "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
- "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "19.0.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
- "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "scheduler": "^0.25.0"
- },
- "peerDependencies": {
- "react": "^19.0.0"
- }
- },
- "node_modules/react-hot-toast": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.1.tgz",
- "integrity": "sha512-54Gq1ZD1JbmAb4psp9bvFHjS7lje+8ubboUmvKZkCsQBLH6AOpZ9JemfRvIdHcfb9AZXRaFLrb3qUobGYDJhFQ==",
- "license": "MIT",
- "dependencies": {
- "csstype": "^3.1.3",
- "goober": "^2.1.16"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "react": ">=16",
- "react-dom": ">=16"
- }
+ "integrity": "sha512-0RgL6n1qmxdkUgvXFnmG/J+Lv8HWjwnWmULtu/omMxRUV9KhD/8x3sL7DmanUvEOi5wX4xTbef1sKe5NzqGm7g=="
},
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.9.2"
@@ -550,28 +498,18 @@
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
- "dev": true,
"license": "MIT"
},
- "node_modules/scheduler": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
- "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
- "license": "MIT",
- "peer": true
- },
"node_modules/spitroast": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/spitroast/-/spitroast-1.4.4.tgz",
"integrity": "sha512-S69rzIFjbGoEW5YCLpm1kEdqMEYqC09lmE1ZMY4gyUXfke0wi9qZjKYa0DDSv5eIy/D+/UGJT8yxgJddU3oqlA==",
- "dev": true,
"license": "CC0-1.0"
},
"node_modules/type-fest": {
- "version": "4.34.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.34.0.tgz",
- "integrity": "sha512-Qcg88ZJsJvRcUijtD6supagRSDf0y1FPZh4NroJpwRkoPYj6gGNidREwTgDuC0Pmq0PVAAzL8C8BZW7xhx5Q4A==",
- "dev": true,
+ "version": "4.34.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.34.1.tgz",
+ "integrity": "sha512-6kSc32kT0rbwxD6QL1CYe8IqdzN/J/ILMrNK+HMQCKH3insCDRY/3ITb0vcBss0a3t72fzh2YSzj8ko1HgwT3g==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=16"
@@ -584,17 +522,15 @@
"version": "0.54.0",
"resolved": "https://registry.npmjs.org/voby/-/voby-0.54.0.tgz",
"integrity": "sha512-hH8LXcP0QR4J6nnzfSWGD13onq7hqdc/ya1r1Bb+TxibtECYKZRO1m4HdSU4RcE7MdAaQwR5pwgd+hqXCqk2OA==",
- "dev": true,
"dependencies": {
"htm": "^3.1.1",
"oby": "^14.3.0"
}
},
"node_modules/zod": {
- "version": "3.24.1",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
- "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
- "dev": true,
+ "version": "3.24.2",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
+ "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
diff --git a/plugins/package.json b/plugins/package.json
index 070571d..f679e72 100644
--- a/plugins/package.json
+++ b/plugins/package.json
@@ -6,10 +6,10 @@
"build": "node ./build.js"
},
"devDependencies": {
- "esbuild": "^0.18.13",
- "neptune-types": "^1.0.0"
+ "esbuild": "^0.18.13"
},
"dependencies": {
- "react-hot-toast": "^2.5.1"
+ "canvas-confetti": "^1.9.3",
+ "neptune-types": "^1.0.1"
}
}
diff --git a/plugins/plugins/copy-lyrics/dist/index.js b/plugins/plugins/copy-lyrics/dist/index.js
new file mode 100644
index 0000000..26bfe08
--- /dev/null
+++ b/plugins/plugins/copy-lyrics/dist/index.js
@@ -0,0 +1,14 @@
+var p=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var v=(t,e)=>()=>(t&&(e=t(t=0)),e);var T=(t,e)=>{for(var n in e)p(t,n,{get:e[n],enumerable:!0})},R=(t,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of S(e))!b.call(t,r)&&r!==n&&p(t,r,{get:()=>e[r],enumerable:!(a=w(e,r))||a.enumerable});return t};var L=t=>R(p({},"__esModule",{value:!0}),t);var E={};T(E,{Tracer:()=>u,libTrace:()=>N});import{actions as f}from"@neptune";var u,N,y=v(()=>{"use strict";u=t=>{let e=o=>{let c=(...i)=>{o(t,...i)};return c.withContext=i=>(...m)=>{o(t,i,...m)},c},n=e(console.log),a=e(console.warn),r=e(console.error),g=e(console.debug),s=(o,c,i)=>{let m=l=>{o(l),c({message:`${t} - ${l}`,category:"OTHER",severity:i})};return m.withContext=l=>{let C=o.withContext(l);return d=>{C(d),d instanceof Error&&(d=d.message),c({message:`${t}.${l} - ${d}`,category:"OTHER",severity:i})}},m};return{log:n,warn:a,err:r,debug:g,msg:{log:s(n,f.message.messageInfo,"INFO"),warn:s(a,f.message.messageWarn,"WARN"),err:s(r,f.message.messageError,"ERROR")}}},N=u("[lib]")});y();y();var h=u("[Copy Lyrics]"),A=`
+[class^="lyricsText"]>div>span {
+ user-select: text;
+ cursor: text;
+
+}
+
+::selection {
+ background:rgb(0, 0, 0);
+ color:rgb(255, 255, 255);
+}
+`;function O(t){let e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.head.appendChild(e)}function $(t){let e=document.createElement("textarea");e.value=t,e.style.position="fixed",document.body.appendChild(e),e.select();try{if(!document.execCommand("copy"))throw new Error("Failed to copy text.")}catch(n){h.msg.err(n)}finally{document.body.removeChild(e)}}O(A);var x=!1;document.addEventListener("mousedown",function(){x=!0});document.addEventListener("mouseup",function(t){if(x){let e=window.getSelection();if(e.toString().length>0){let n=[],g=e.getRangeAt(0).commonAncestorContainer.getElementsByTagName("span");for(let o of g)e.containsNode(o,!0)&&n.push(o);let s="";n.forEach(o=>{s+=o.textContent+`
+`,[...o.classList].some(c=>c.startsWith("endOfStanza--"))&&(s+=`
+`)}),s=s.trim(),$(s),h.msg.log("Copied to clipboard!"),window.getSelection&&e.removeAllRanges()}x=!1}});function F(){styleElement&&styleElement.parentNode&&styleElement.parentNode.removeChild(styleElement),document.removeEventListener("mousedown",onMouseDown),document.removeEventListener("mouseup",onMouseUp)}export{F as onUnload};
diff --git a/plugins/plugins/copy-lyrics/dist/manifest.json b/plugins/plugins/copy-lyrics/dist/manifest.json
new file mode 100644
index 0000000..7523d9b
--- /dev/null
+++ b/plugins/plugins/copy-lyrics/dist/manifest.json
@@ -0,0 +1 @@
+{"name":"Copy Lyrics","description":"A working neptune plugin that allows the user to copy the lyrics of a song selecting it.","author":"itzzexcel@github","hash":"aeef96d8ab14451ebe3f42446de81230","metafile":{"inputs":{"plugins/copy-lyrics/src/tracer.js":{"bytes":1596,"imports":[{"path":"@neptune","kind":"import-statement","external":true}],"format":"esm"},"plugins/copy-lyrics/src/index.js":{"bytes":2930,"imports":[{"path":"plugins/copy-lyrics/src/tracer.js","kind":"import-statement","original":"./tracer"},{"path":"plugins/copy-lyrics/src/tracer.js","kind":"require-call","original":"./tracer"}],"format":"esm"}},"outputs":{"plugins/copy-lyrics/dist/index.js":{"imports":[{"path":"@neptune","kind":"import-statement","external":true}],"exports":["onUnload"],"entryPoint":"plugins/copy-lyrics/src/index.js","inputs":{"plugins/copy-lyrics/src/tracer.js":{"bytesInOutput":693},"plugins/copy-lyrics/src/index.js":{"bytesInOutput":1362}},"bytes":2525}}}}
\ No newline at end of file
diff --git a/plugins/plugins/copy-lyrics/package.json b/plugins/plugins/copy-lyrics/package.json
index 82e2b02..d020e40 100644
--- a/plugins/plugins/copy-lyrics/package.json
+++ b/plugins/plugins/copy-lyrics/package.json
@@ -1,5 +1,6 @@
{
"dependencies": {
- "canvas-confetti": "^1.6.0"
+ "canvas-confetti": "^1.6.0",
+ "neptune-types": "1.0.1"
}
}
\ No newline at end of file
diff --git a/plugins/plugins/copy-lyrics/src/index.js b/plugins/plugins/copy-lyrics/src/index.js
index c2fb08f..4d193c6 100644
--- a/plugins/plugins/copy-lyrics/src/index.js
+++ b/plugins/plugins/copy-lyrics/src/index.js
@@ -1,27 +1,36 @@
/*
- * TODO: Check for the span to be part of the lyrics div.
- *
+TODO: Check for the span to be part of the lyrics div.
*/
-import toast, { Toaster } from 'react-hot-toast';
+require("./tracer")
+import { Tracer } from "./tracer";
+
+const trace = Tracer("[Copy Lyrics]");
const unlockSelection = `
[class^="lyricsText"]>div>span {
user-select: text;
cursor: text;
-}`;
+
+}
+
+::selection {
+ background:rgb(0, 0, 0);
+ color:rgb(255, 255, 255);
+}
+`;
function ApplyCSS(style) {
- const styleElement = document.createElement('style');
- styleElement.type = 'text/css';
- if (styleElement.styleSheet)
- styleElement.styleSheet.cssText = style;
- else
- styleElement.appendChild(document.createTextNode(style));
+ const styleElement = document.createElement('style');
+ styleElement.type = 'text/css';
+ if (styleElement.styleSheet)
+ styleElement.styleSheet.cssText = style;
+ else
+ styleElement.appendChild(document.createTextNode(style));
- document.head.appendChild(styleElement);
+ document.head.appendChild(styleElement);
}
-function SetClipboar(text) {
+function SetClipboard(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed'; // Avoid scrolling to the bottom
@@ -30,15 +39,11 @@ function SetClipboar(text) {
try {
const success = document.execCommand('copy');
- if (success) {
- console.log('Text copied to clipboard:', text);
- toast.success('Copied to clipboard!');
- } else {
+ if (!success)
throw new Error('Failed to copy text.');
- }
+
} catch (err) {
- console.error('Failed to copy text:', err);
- toast.error('Failed to copy to clipboard!');
+ trace.msg.err(err);
} finally {
document.body.removeChild(textarea);
}
@@ -52,24 +57,47 @@ document.addEventListener('mousedown', function() {
isSelecting = true;
});
-document.addEventListener('mouseup', function() {
+document.addEventListener('mouseup', function (event) {
if (isSelecting) {
const selection = window.getSelection();
if (selection.toString().length > 0) {
- let text = selection.toString();
- SetClipboar(text);
- toast.success("Copied to clipboard!");
- if (window.getSelection) {
- const selection = window.getSelection();
- selection.removeAllRanges();
- }
- } else {
+ const selectedSpans = [];
+ const ranges = selection.getRangeAt(0);
+ const container = ranges.commonAncestorContainer;
+ // Get all spans within the selection
+ const spans = container.getElementsByTagName('span');
+ for (let span of spans) {
+ if (selection.containsNode(span, true)) {
+ selectedSpans.push(span);
+ }
+ }
+
+ // Concatenate text from selected spans
+ let text = '';
+ selectedSpans.forEach(span => {
+ text += span.textContent + '\n';
+ if ([...span.classList].some(className => className.startsWith('endOfStanza--'))) {
+ text += '\n';
+ }
+ });
+ text = text.trim();
+
+ SetClipboard(text);
+ trace.msg.log("Copied to clipboard!");
+ if (window.getSelection) {
+ selection.removeAllRanges();
+ }
}
isSelecting = false;
}
});
export function onUnload() {
- console.log("Goodbye world!");
+ if (styleElement && styleElement.parentNode) {
+ styleElement.parentNode.removeChild(styleElement);
+ }
+
+ document.removeEventListener('mousedown', onMouseDown);
+ document.removeEventListener('mouseup', onMouseUp);
}
diff --git a/plugins/plugins/copy-lyrics/src/tracer.js b/plugins/plugins/copy-lyrics/src/tracer.js
new file mode 100644
index 0000000..f18bcd3
--- /dev/null
+++ b/plugins/plugins/copy-lyrics/src/tracer.js
@@ -0,0 +1,55 @@
+// Based on https://github.com/Inrixia/neptune-plugins/blob/3d28c9ea3252782da830698032dbb49dbe5b9fd6/plugins/_lib/trace.ts
+// Credits to inrixia
+
+import { actions } from "@neptune";
+
+export const Tracer = (source) => {
+ const createLogger = (logger) => {
+ const _logger = (...data) => {
+ logger(source, ...data);
+ return undefined;
+ };
+ _logger.withContext = (context) => (...data) => {
+ logger(source, context, ...data);
+ return undefined;
+ };
+ return _logger;
+ };
+
+ const log = createLogger(console.log);
+ const warn = createLogger(console.warn);
+ const err = createLogger(console.error);
+ const debug = createLogger(console.debug);
+
+ const createMessager = (logger, messager, severity) => {
+ const _messager = (message) => {
+ logger(message);
+ messager({ message: `${source} - ${message}`, category: "OTHER", severity });
+ return undefined;
+ };
+ _messager.withContext = (context) => {
+ const loggerWithContext = logger.withContext(context);
+ return (message) => {
+ loggerWithContext(message);
+ if (message instanceof Error) message = message.message;
+ messager({ message: `${source}.${context} - ${message}`, category: "OTHER", severity });
+ return undefined;
+ };
+ };
+ return _messager;
+ };
+
+ return {
+ log,
+ warn,
+ err,
+ debug,
+ msg: {
+ log: createMessager(log, actions.message.messageInfo, "INFO"),
+ warn: createMessager(warn, actions.message.messageWarn, "WARN"),
+ err: createMessager(err, actions.message.messageError, "ERROR"),
+ },
+ };
+};
+
+export const libTrace = Tracer("[lib]");
\ No newline at end of file
diff --git a/themes/black-neptune-theme.css b/themes/black-neptune-theme.css
index 09582dc..7cf5622 100644
--- a/themes/black-neptune-theme.css
+++ b/themes/black-neptune-theme.css
@@ -6,8 +6,6 @@
}
*/
-
-
::-webkit-scrollbar {
display: none;
}
@@ -24,6 +22,15 @@
--wave-color-solid-accent-dark: gray;
}
+[class^="followingButton"],
+[title="Unfollow"],
+[title="Follow"],
+[title="Unfollow"]>span,
+[title="Follow"]>span {
+ background-color: var(--wave-color-solid-rainbow-yellow-fill) !important;
+ color: var(--wave-color-solid-base-brighter);
+}
+
[class^="_wave-badge-color-max"] {
color: black !important;
background-color: var(--wave-color-solid-accent-fill);
@@ -61,13 +68,13 @@
}
[class^="ReactVirtualized__Grid"] {
- border: 1px solid rgb(25, 25, 25);
border-radius: 10px;
margin: 5px;
}
[class^="ReactVirtualized__Grid__innerScrollContainer"] {
- border: 1px solid rgba(0, 0, 0, 0);
+ border: none;
+ margin: 5px;
}
[class^="button"]>span {
@@ -90,7 +97,17 @@
display: none !important;
}
-[class^="headerButtons"]>button {
+[data-test="current-media-imagery"] {
+ border: 0 !important;
+ margin: none;
+}
+
+[class^="imageBorder"] {
+ display: none;
+}
+
+[class^="headerButtons"]>button,
+[data-test="toggle-picture-in-picture"] {
background-color: var(--wave-color-solid-accent-fill) !important;
color: black;
}
@@ -109,8 +126,8 @@
border: 0px none;
}
-[class^="feedSidebarVStack"] {
- background-color: #1a1a1a;
+[data-test="feed-sidebar"] {
+ margin-top: 10px;
}
[class^="player"] {
@@ -141,7 +158,11 @@
}
[class^="actionList"] {
- background-color: #1a1a1a;
+ background-color: transparent;
+ border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin) !important;
+ margin: 5px;
+ border-radius: 5px;
+ padding: 10px;
}
button[data-test="request-fullscreen"],
@@ -174,10 +195,14 @@ button[data-test="close-now-playing"]:hover {
opacity: 1;
}
-[class^="contextMenu"]>div, [data-test="main-layout-header"], [data-test="feed-sidebar"], [data-test="stream-metadata"] {
- background-color: rgba(0, 0, 0, 0.5);
- backdrop-filter: blur(15px);
- border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin);
+[class^="contextMenu"]>div,
+[data-test="main-layout-header"],
+[data-test="feed-sidebar"],
+[data-test="stream-metadata"],
+[class^="player"] {
+ background-color: rgba(0, 0, 0, 0.8) !important;
+ backdrop-filter: blur(10px);
+ border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin) !important;
}
[data-wave-color=textUrl] {
@@ -188,12 +213,16 @@ button[data-test="close-now-playing"]:hover {
margin-top: 7.5px;
}
-[data-test="play-all"]>div>*, [data-test="shuffle-all"]>div>*, [data-test="play-all"], [data-test="shuffle-all"] {
+[data-test="play-all"]>div>*,
+[data-test="shuffle-all"]>div>*,
+[data-test="play-all"],
+[data-test="shuffle-all"] {
color: var(--wave-color-solid-accent-fill) !important;
background-color: transparent !important;
}
-[class^="__NEPTUNE_PAGE"], [data-test="main"] {
+[class^="__NEPTUNE_PAGE"],
+[data-test="main"] {
margin-top: 35px;
}
@@ -206,4 +235,15 @@ button[data-test="close-now-playing"]:hover {
[data-test="button-release-notes"]:hover {
background-color: lightgray !important;
transition: none !important;
+}
+
+#playQueueSidebar {
+ top: 50px !important;
+ border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin);
+ margin: 2px;
+ margin-right: -5px !important;
+}
+
+[class^="bottomGradient"] {
+ visibility: hidden;
}
\ No newline at end of file