@purpleproser/soundboard-downloader-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # @purpleproser/soundboard-downloader-cli
2
+
3
+ A command-line tool to download soundboard sounds from MyInstants.
4
+
5
+ **npm Package**: `@purpleproser/soundboard-downloader-cli`
6
+ **GitHub Repository**: [blacksagres/soundboard-downloader-cli](https://github.com/blacksagres/soundboard-downloader-cli) Built with TypeScript and Node.js.
7
+
8
+ ## Features
9
+
10
+ - 🔍 Search for sounds by name using interactive prompts
11
+ - 🎵 Preview sounds by playing them in your browser
12
+ - ⬇️ Download individual sounds to your local machine
13
+ - ✨ Simple and easy-to-use interactive interface
14
+
15
+ ## Tech Stack
16
+
17
+ - **TypeScript** - Type-safe development
18
+ - **Node.js** - Runtime environment
19
+ - **Inquirer** - Interactive CLI prompts
20
+ - **jsdom** - HTML parsing and DOM manipulation
21
+ - **ora** - Elegant terminal spinners
22
+ - **open** - Opens URLs in the user's browser
23
+
24
+ ## Prerequisites
25
+
26
+ - Node.js 16.x or higher
27
+
28
+ ## Installation
29
+
30
+ ### Local Installation
31
+
32
+ 1. Clone this repository:
33
+
34
+ ```bash
35
+ git clone https://github.com/blacksagres/soundboard-downloader-cli.git
36
+ ```
37
+
38
+ 2. Navigate to the project directory:
39
+
40
+ ```bash
41
+ cd soundboard-downloader-cli
42
+ ```
43
+
44
+ 3. Install dependencies:
45
+
46
+ ```bash
47
+ npm install
48
+ ```
49
+
50
+ ### Global Installation
51
+
52
+ Install globally to use the `soundboard-downloader` command anywhere:
53
+
54
+ ```bash
55
+ npm install -g @purpleproser/soundboard-downloader-cli
56
+ ```
57
+
58
+ Or from the project directory:
59
+
60
+ ```bash
61
+ npm link
62
+ ```
63
+
64
+ **Note**: This package uses the `@purpleproser` npm scope (my npm username) while the GitHub repository remains under `blacksagres`. Make sure to include the `@purpleproser/` prefix when installing!
65
+
66
+ **For Developers**: If you fork this project and want to publish your own version, either:
67
+ 1. Use a different package name, or
68
+ 2. Create your own npm scope and update the package name, or
69
+ 3. Add `"publishConfig": { "access": "public" }` to your package.json
70
+
71
+ ## Usage
72
+
73
+ ### Development Mode
74
+
75
+ Run directly with ts-node (no build required):
76
+
77
+ ```bash
78
+ npm start
79
+ ```
80
+
81
+ ### Production Build
82
+
83
+ Build the TypeScript project:
84
+
85
+ ```bash
86
+ npm run build
87
+ ```
88
+
89
+ Then run the compiled JavaScript:
90
+
91
+ ```bash
92
+ node dist/main.js
93
+ ```
94
+
95
+ ### Global Command
96
+
97
+ If installed globally:
98
+
99
+ ```bash
100
+ soundboard-downloader
101
+ ```
102
+
103
+ ### Interactive Workflow
104
+
105
+ The CLI will guide you through an interactive process:
106
+
107
+ 1. **Search**: You'll be prompted to enter what sound effects you're looking for
108
+ 2. **Select**: Choose from the list of matching sounds
109
+ 3. **Action**: Decide whether to play the sound in your browser or download it to your `./temp/` directory
110
+
111
+ ### Example Workflow
112
+
113
+ ```bash
114
+ $ npm start
115
+
116
+ ? What sound effects are you looking for? wilhelm scream
117
+ ✔ Loading result...
118
+ ? Which one to download? (Use arrow keys)
119
+ > Wilhelm Scream - Original
120
+ Wilhelm Scream - Remastered
121
+ Wilhelm Scream - Short Version
122
+ ? Selected: Wilhelm Scream - Original
123
+ ? (Use arrow keys)
124
+ > Download
125
+ Play
126
+ ```
127
+
128
+ ## Development
129
+
130
+ ### Project Structure
131
+
132
+ ```
133
+ src/
134
+ ├── main.ts # Entry point
135
+ ├── api/
136
+ │ └── my-instants.api.ts # API layer for MyInstants
137
+ ├── components/ # CLI components
138
+ └── service/
139
+ └── my-instants.service.ts # Business logic
140
+ ```
141
+
142
+ ### Available Scripts
143
+
144
+ - `npm start` - Run in development mode with ts-node
145
+ - `npm run build` - Compile TypeScript to JavaScript
146
+ - `npm test` - Run tests (not yet implemented)
147
+
148
+ ### Download Location
149
+
150
+ Downloaded sounds are saved to the `./temp/` directory in the project root.
151
+
152
+ ## Contributing
153
+
154
+ Contributions are welcome! Please open an issue or submit a pull request.
155
+
156
+ ## Legal Disclaimer
157
+
158
+ **Important Notice About Copyright and Usage:**
159
+
160
+ This tool is an automation layer that simulates what a real user would do manually on the MyInstants website. It uses the official download functionality provided by MyInstants and does not bypass any restrictions or access protected content.
161
+
162
+ **User Responsibility:**
163
+
164
+ - You are solely responsible for ensuring that your use of downloaded content complies with all applicable laws and MyInstants' Terms of Service
165
+ - This application is not responsible for any copyright infringement that may occur through the use of downloaded audio files
166
+ - Many sound effects may be copyrighted - check the specific rights and licenses for each sound before using it
167
+
168
+ **Experimental Nature:**
169
+ This project is a simple experiment with Node.js and CLI development. It is provided "as is" without warranty of any kind. The developers are not affiliated with MyInstants and cannot guarantee the continued functionality of this tool.
170
+
171
+ ## License
172
+
173
+ This project is licensed under the MIT License.
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * Fetch the html from myinstants.com.
4
+ *
5
+ * 1. Query the html for the sound based on name
6
+ * 2 .Then find the corresponding link to that sound
7
+ * 3. Transform the found html nodes to an object with `{ label: string, download_url: string }`
8
+ * 4. List them in the console - a user can pick one of the list (search in terminal)
9
+ * 5. Download the sound (donwload folder from the user)
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getNodeDownloadPage = exports.getSoundNodes = void 0;
13
+ const getSoundNodes = async (searchString) => {
14
+ let page = 1;
15
+ const result = [];
16
+ const escapedSearchParam = encodeURIComponent(searchString);
17
+ /**
18
+ * Yeah so that page does a little trick to make an infinite scroll.
19
+ *
20
+ * Whenever you hit the page in your browser, there's a script that will try to fetch the next page and
21
+ * append the results to the current one, until it hits a 404 (ran out of pages). Here we try to do the same.
22
+ *
23
+ * One idea was to append this all into one string document but we just return 1 array with all
24
+ * the pages we found. Then he service layer can crunch on this to determine what to pick.
25
+ */
26
+ while (true) {
27
+ const url = `https://www.myinstants.com/en/search/?name=${escapedSearchParam}&page=${page}`;
28
+ const response = await fetch(url);
29
+ if (response.ok) {
30
+ const htmlResult = await response.text();
31
+ result.push(htmlResult);
32
+ page++;
33
+ continue;
34
+ }
35
+ break;
36
+ }
37
+ return result;
38
+ };
39
+ exports.getSoundNodes = getSoundNodes;
40
+ const getNodeDownloadPage = async (soundNodeDetailsURL) => {
41
+ const root = `https://www.myinstants.com${soundNodeDetailsURL}`;
42
+ const response = await fetch(root);
43
+ return await response.text();
44
+ };
45
+ exports.getNodeDownloadPage = getNodeDownloadPage;
46
+ //# sourceMappingURL=my-instants.api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"my-instants.api.js","sourceRoot":"","sources":["../../src/api/my-instants.api.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEI,MAAM,aAAa,GAAG,KAAK,EAAE,YAAoB,EAAE,EAAE;IAC1D,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAE5D;;;;;;;;OAQG;IAEH,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,8CAA8C,kBAAkB,SAAS,IAAI,EAAE,CAAC;QAC5F,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAExB,IAAI,EAAE,CAAC;YAEP,SAAS;QACX,CAAC;QAED,MAAM;IACR,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAjCW,QAAA,aAAa,iBAiCxB;AAEK,MAAM,mBAAmB,GAAG,KAAK,EAAE,mBAA2B,EAAE,EAAE;IACvE,MAAM,IAAI,GAAG,6BAA6B,mBAAmB,EAAE,CAAC;IAEhE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC/B,CAAC,CAAC;AANW,QAAA,mBAAmB,uBAM9B"}
package/dist/main.js ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const my_instants_service_1 = require("./service/my-instants.service");
5
+ const ora_1 = require("ora");
6
+ const prompts_1 = require("@inquirer/prompts");
7
+ const open_1 = require("open");
8
+ const file_downloader_service_1 = require("./service/file-downloader.service");
9
+ (async function () {
10
+ const answer = await (0, prompts_1.input)({
11
+ message: "What sound effects are you looking for?",
12
+ });
13
+ const spinner = (0, ora_1.default)({
14
+ text: "Loading result...",
15
+ color: "magenta",
16
+ spinner: "bouncingBall",
17
+ }).start();
18
+ const sounds = await (0, my_instants_service_1.getSoundNodes)(answer);
19
+ spinner.stop();
20
+ const selection = await (0, prompts_1.select)({
21
+ message: "Which one to download?",
22
+ choices: sounds.map((sound) => ({
23
+ name: sound.label,
24
+ value: `${sound.label}||${sound.download_url}`,
25
+ })),
26
+ });
27
+ const [label, downloadUrl] = selection.split("||");
28
+ if (!downloadUrl) {
29
+ throw new ReferenceError(`There is no download URL for: ${label}`);
30
+ }
31
+ const actions = [
32
+ {
33
+ name: "Download",
34
+ value: "action:download",
35
+ },
36
+ {
37
+ name: "Play",
38
+ value: "action:play",
39
+ },
40
+ ];
41
+ const action = await (0, prompts_1.select)({
42
+ message: `Selected: ${label}`,
43
+ choices: actions,
44
+ });
45
+ if (action === "action:play") {
46
+ (0, open_1.default)(downloadUrl);
47
+ }
48
+ if (action === "action:download") {
49
+ const downloadSpinner = (0, ora_1.default)({
50
+ text: "Downloading file...",
51
+ color: "cyan",
52
+ spinner: "growHorizontal",
53
+ }).start();
54
+ const downloadFileName = downloadUrl.split("/").pop();
55
+ (0, file_downloader_service_1.downloadFile)(downloadUrl, {
56
+ destination: `./temp/${downloadFileName}`,
57
+ onStart: () => downloadSpinner.start(),
58
+ onFinish: () => downloadSpinner.stop(),
59
+ });
60
+ }
61
+ })();
62
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;AAEA,uEAA8D;AAC9D,6BAAsB;AACtB,+CAAkD;AAClD,+BAAwB;AACxB,+EAAiE;AAEjE,CAAC,KAAK;IACJ,MAAM,MAAM,GAAG,MAAM,IAAA,eAAK,EAAC;QACzB,OAAO,EAAE,yCAAyC;KACnD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC;QAClB,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEX,MAAM,MAAM,GAAG,MAAM,IAAA,mCAAa,EAAC,MAAM,CAAC,CAAC;IAE3C,OAAO,CAAC,IAAI,EAAE,CAAC;IAEf,MAAM,SAAS,GAAG,MAAM,IAAA,gBAAM,EAAC;QAC7B,OAAO,EAAE,wBAAwB;QACjC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC9B,IAAI,EAAE,KAAK,CAAC,KAAK;YACjB,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,EAAW;SACxD,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CAAC,iCAAiC,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,OAAO,GAAG;QACd;YACE,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,iBAAiB;SACzB;QACD;YACE,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,aAAa;SACrB;KACO,CAAC;IAEX,MAAM,MAAM,GAAG,MAAM,IAAA,gBAAM,EAAC;QAC1B,OAAO,EAAE,aAAa,KAAK,EAAE;QAC7B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC7B,IAAA,cAAI,EAAC,WAAW,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;QACjC,MAAM,eAAe,GAAG,IAAA,aAAG,EAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC,KAAK,EAAE,CAAC;QAEX,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAEtD,IAAA,sCAAY,EAAC,WAAW,EAAE;YACxB,WAAW,EAAE,UAAU,gBAAgB,EAAE;YACzC,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE;YACtC,QAAQ,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE;SACvC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.downloadFile = void 0;
4
+ const https = require("https");
5
+ const fs = require("fs");
6
+ const downloadFile = (url, config) => {
7
+ const file = fs.createWriteStream(config.destination);
8
+ https.get(url, function (response) {
9
+ response.pipe(file);
10
+ file.on("open", () => {
11
+ config.onStart?.();
12
+ });
13
+ file.on("finish", () => {
14
+ file.close();
15
+ config.onFinish?.();
16
+ console.log("Download Completed");
17
+ });
18
+ });
19
+ };
20
+ exports.downloadFile = downloadFile;
21
+ //# sourceMappingURL=file-downloader.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-downloader.service.js","sourceRoot":"","sources":["../../src/service/file-downloader.service.ts"],"names":[],"mappings":";;;AAAA,+BAA+B;AAC/B,yBAAyB;AAElB,MAAM,YAAY,GAAG,CAC1B,GAAW,EACX,MAIC,EACD,EAAE;IACF,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEtD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,QAAQ;QAC/B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpB,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACnB,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAvBW,QAAA,YAAY,gBAuBvB"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSoundNodes = void 0;
4
+ const my_instants_api_1 = require("../api/my-instants.api");
5
+ const jsdom = require("jsdom");
6
+ const getDownloadUrl = async (originalUrl) => {
7
+ if (!originalUrl) {
8
+ return "not-found";
9
+ }
10
+ /**
11
+ * For example, this is what the url looks like from the link:
12
+ *
13
+ * '/en/instant/nemesis-resident-evil-3-stars/'
14
+ *
15
+ * And we want it to be like this:
16
+ *
17
+ * 'nemesis-resident-evil-3-stars'
18
+ *
19
+ * To eventually combine with the download url template and make a final link.
20
+ */
21
+ const cleanSoundName = originalUrl
22
+ .replace("/en/instant/", "")
23
+ .replace("/", "");
24
+ const downloadPage = await (0, my_instants_api_1.getNodeDownloadPage)(originalUrl);
25
+ const downloadLink = Array.from(new jsdom.JSDOM(downloadPage).window.document.querySelectorAll("a")).find((node) => {
26
+ return node.href.includes(".mp3") && node.hasAttribute("download");
27
+ });
28
+ if (downloadLink) {
29
+ return `https://www.myinstants.com${downloadLink.href}`;
30
+ }
31
+ return "not-found";
32
+ };
33
+ const getSoundNodes = async (searchString) => {
34
+ const result = await (0, my_instants_api_1.getSoundNodes)(searchString);
35
+ const allLabels = [];
36
+ const allDownloadLinks = [];
37
+ for (const page of result) {
38
+ const document = new jsdom.JSDOM(page);
39
+ document.window.document
40
+ .querySelectorAll("div.instant > a.instant-link")
41
+ .forEach((node) => {
42
+ allLabels.push(node.textContent);
43
+ allDownloadLinks.push(getDownloadUrl(node.getAttribute("href")));
44
+ });
45
+ }
46
+ const allLinksResolved = await Promise.all(allDownloadLinks);
47
+ const finalList = allLabels.map((label, index) => ({
48
+ label,
49
+ download_url: allLinksResolved[index] ?? "not-found",
50
+ }));
51
+ return finalList.toSorted((a, b) => a.label.localeCompare(b.label));
52
+ };
53
+ exports.getSoundNodes = getSoundNodes;
54
+ //# sourceMappingURL=my-instants.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"my-instants.service.js","sourceRoot":"","sources":["../../src/service/my-instants.service.ts"],"names":[],"mappings":";;;AAAA,4DAGgC;AAChC,+BAA+B;AAE/B,MAAM,cAAc,GAAG,KAAK,EAAE,WAA0B,EAAE,EAAE;IAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,cAAc,GAAG,WAAW;SAC/B,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAEpB,MAAM,YAAY,GAAG,MAAM,IAAA,qCAAmB,EAAC,WAAW,CAAC,CAAC;IAE5D,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAC7B,IAAI,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,CACpE,CAAC,IAAI,CAAC,CAAC,IAAuB,EAAE,EAAE;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,6BAA6B,YAAY,CAAC,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEK,MAAM,aAAa,GAAG,KAAK,EAAE,YAAoB,EAAE,EAAE;IAC1D,MAAM,MAAM,GAAG,MAAM,IAAA,+BAAgB,EAAC,YAAY,CAAC,CAAC;IAEpD,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,MAAM,gBAAgB,GAA2B,EAAE,CAAC;IAEpD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEvC,QAAQ,CAAC,MAAM,CAAC,QAAQ;aACrB,gBAAgB,CAAC,8BAA8B,CAAC;aAChD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAChB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACjC,gBAAgB,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACjD,KAAK;QACL,YAAY,EAAE,gBAAgB,CAAC,KAAK,CAAC,IAAI,WAAW;KACrD,CAAC,CAAC,CAAC;IAEJ,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC;AAzBW,QAAA,aAAa,iBAyBxB"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@purpleproser/soundboard-downloader-cli",
3
+ "version": "1.0.0",
4
+ "description": "Easily download sounds from myinstants.com using this interactive CLI tool",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "author": "blacksagres",
10
+ "type": "commonjs",
11
+ "main": "dist/main.js",
12
+ "bin": {
13
+ "soundboard-downloader": "./dist/main.js"
14
+ },
15
+ "scripts": {
16
+ "test": "echo \"Error: no test specified\" && exit 1",
17
+ "start": "ts-node ./src/main.ts",
18
+ "build": "tsc",
19
+ "prepare": "npm run build",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "soundboard",
24
+ "myinstants",
25
+ "cli",
26
+ "downloader",
27
+ "audio",
28
+ "interactive"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/blacksagres/soundboard-downloader-cli.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/blacksagres/soundboard-downloader-cli/issues"
36
+ },
37
+ "homepage": "https://github.com/blacksagres/soundboard-downloader-cli#readme",
38
+ "devDependencies": {
39
+ "@types/jsdom": "^27.0.0",
40
+ "@types/node": "^25.2.3",
41
+ "ts-node": "^10.9.2",
42
+ "typescript": "^5.9.3"
43
+ },
44
+ "dependencies": {
45
+ "@inquirer/prompts": "^8.2.0",
46
+ "jsdom": "^28.0.0",
47
+ "open": "^11.0.0",
48
+ "ora": "^9.3.0"
49
+ }
50
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ // Visit https://aka.ms/tsconfig to read more about this file
3
+ "compilerOptions": {
4
+ // File Layout
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+
8
+ // Environment Settings
9
+ // See also https://aka.ms/tsconfig/module
10
+ "module": "commonjs",
11
+ "target": "esnext",
12
+ // For nodejs:
13
+ "lib": ["esnext"],
14
+ "types": ["node"],
15
+
16
+ // Other Outputs
17
+ "sourceMap": true,
18
+ "declaration": true,
19
+ "declarationMap": true,
20
+
21
+ // Stricter Typechecking Options
22
+ "noUncheckedIndexedAccess": true,
23
+ "exactOptionalPropertyTypes": true,
24
+
25
+ // Style Options
26
+ // "noImplicitReturns": true,
27
+ // "noImplicitOverride": true,
28
+ // "noUnusedLocals": true,
29
+ // "noUnusedParameters": true,
30
+ // "noFallthroughCasesInSwitch": true,
31
+ // "noPropertyAccessFromIndexSignature": true,
32
+
33
+ // Recommended Options
34
+ "strict": true,
35
+ "jsx": "react-jsx",
36
+ "verbatimModuleSyntax": false,
37
+ "isolatedModules": true,
38
+ "noUncheckedSideEffectImports": true,
39
+ "moduleDetection": "force",
40
+ "skipLibCheck": true
41
+ }
42
+ }