voicci 1.0.3 → 1.0.7
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/lib/book-finder.js +0 -2
- package/package.json +1 -1
- package/scripts/postinstall.js +192 -63
package/lib/book-finder.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voicci",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "AI-Powered Audiobook Generator for Claude Code, OpenCode & AI Code Editors. Convert books and PDFs to audiobooks using natural language.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli/index.js",
|
package/scripts/postinstall.js
CHANGED
|
@@ -3,31 +3,36 @@
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import os from 'os';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { execFileSync } from 'child_process';
|
|
6
8
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
# Auto-installed via npm package
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// Use unique name to avoid conflicts with SSH shorthand skills
|
|
13
|
+
const SKILL_NAME = 'voicci-audiobook.md';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
const SKILL_CONTENT = `---
|
|
16
|
+
description: "Voicci - AI audiobook generator CLI"
|
|
17
|
+
argument-hint: "COMMAND_OR_FILE"
|
|
18
|
+
---
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
A command-line tool that converts books and PDFs into audiobooks using XTTS v2 AI voice synthesis. It also provides AI text summarization.
|
|
20
|
+
# Voicci - AI Audiobook Generator
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
Convert books, PDFs, and documents to audiobooks using AI-powered text-to-speech (XTTS v2).
|
|
23
|
+
|
|
24
|
+
## What is Voicci?
|
|
25
|
+
A command-line tool that converts books and PDFs into natural-sounding audiobooks. Also provides AI text summarization.
|
|
21
26
|
|
|
22
27
|
## Common Commands
|
|
23
28
|
|
|
24
|
-
**Search
|
|
29
|
+
**Search and convert a book:**
|
|
25
30
|
\`\`\`bash
|
|
26
31
|
voicci "Lord of the Rings"
|
|
27
32
|
voicci "Attention Is All You Need"
|
|
28
33
|
\`\`\`
|
|
29
34
|
|
|
30
|
-
**Convert a file:**
|
|
35
|
+
**Convert a local file:**
|
|
31
36
|
\`\`\`bash
|
|
32
37
|
voicci mybook.pdf
|
|
33
38
|
voicci document.txt
|
|
@@ -38,13 +43,14 @@ voicci document.txt
|
|
|
38
43
|
voicci --search "The Great Gatsby"
|
|
39
44
|
\`\`\`
|
|
40
45
|
|
|
41
|
-
**Generate summary:**
|
|
46
|
+
**Generate text summary:**
|
|
42
47
|
\`\`\`bash
|
|
43
48
|
voicci summary mybook.pdf
|
|
44
49
|
voicci --summary "1984"
|
|
50
|
+
voicci --with-summary "book.pdf" # Generate both audiobook + summary
|
|
45
51
|
\`\`\`
|
|
46
52
|
|
|
47
|
-
**Check status:**
|
|
53
|
+
**Check job status:**
|
|
48
54
|
\`\`\`bash
|
|
49
55
|
voicci -s # All jobs
|
|
50
56
|
voicci -s <jobId> # Specific job
|
|
@@ -55,6 +61,13 @@ voicci -s <jobId> # Specific job
|
|
|
55
61
|
voicci -l
|
|
56
62
|
\`\`\`
|
|
57
63
|
|
|
64
|
+
**Manage jobs:**
|
|
65
|
+
\`\`\`bash
|
|
66
|
+
voicci --cancel <jobId> # Cancel running job
|
|
67
|
+
voicci --delete <jobId> # Delete audiobook
|
|
68
|
+
voicci --open <jobId> # Open audiobook folder
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
58
71
|
**Configuration:**
|
|
59
72
|
\`\`\`bash
|
|
60
73
|
voicci config show
|
|
@@ -63,67 +76,183 @@ voicci config set-quality best
|
|
|
63
76
|
voicci memory
|
|
64
77
|
\`\`\`
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
voicci
|
|
69
|
-
voicci
|
|
79
|
+
\`\`\`!
|
|
80
|
+
#!/bin/bash
|
|
81
|
+
# Execute voicci with user-provided arguments
|
|
82
|
+
voicci $ARGUMENTS
|
|
70
83
|
\`\`\`
|
|
71
84
|
|
|
72
85
|
## Important Notes
|
|
73
86
|
- Book downloads require copyright compliance (public domain, owned books, academic papers)
|
|
74
87
|
- Processing runs in background - check status with \`voicci -s\`
|
|
75
|
-
- Audiobooks saved to
|
|
88
|
+
- Audiobooks saved to:
|
|
89
|
+
- macOS: \`~/Library/Application Support/voicci/audiobooks/\`
|
|
90
|
+
- Linux: \`~/.local/share/voicci/audiobooks/\`
|
|
76
91
|
- Copyright warning will appear before first book search
|
|
77
92
|
|
|
78
|
-
##
|
|
79
|
-
- "
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
Execute the appropriate command now based on the user's request.
|
|
86
|
-
PROMPT_EOF
|
|
93
|
+
## Usage Examples
|
|
94
|
+
- \`/voicci-audiobook "Lord of the Rings"\` - Search and convert book
|
|
95
|
+
- \`/voicci-audiobook ~/Documents/book.pdf\` - Convert local file
|
|
96
|
+
- \`/voicci-audiobook -s\` - Check all job statuses
|
|
97
|
+
- \`/voicci-audiobook summary book.pdf\` - Generate summary only
|
|
98
|
+
- \`/voicci-audiobook --help\` - Show all options
|
|
87
99
|
`;
|
|
88
100
|
|
|
89
|
-
|
|
101
|
+
// Editor detection configurations
|
|
102
|
+
const EDITORS = {
|
|
103
|
+
'Claude Code': {
|
|
104
|
+
name: 'Claude Code',
|
|
105
|
+
detect: () => {
|
|
106
|
+
const homeDir = os.homedir();
|
|
107
|
+
// Check for claude command or .claude directory
|
|
108
|
+
if (fs.existsSync(path.join(homeDir, '.claude'))) return true;
|
|
109
|
+
try {
|
|
110
|
+
execFileSync('which', ['claude'], { stdio: 'ignore' });
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
skillsDir: () => path.join(os.homedir(), '.claude', 'skills'),
|
|
117
|
+
skillName: SKILL_NAME
|
|
118
|
+
},
|
|
119
|
+
'OpenCode': {
|
|
120
|
+
name: 'OpenCode',
|
|
121
|
+
detect: () => {
|
|
122
|
+
const homeDir = os.homedir();
|
|
123
|
+
// Check for opencode command or config directory
|
|
124
|
+
if (fs.existsSync(path.join(homeDir, '.opencode'))) return true;
|
|
125
|
+
try {
|
|
126
|
+
execFileSync('which', ['opencode'], { stdio: 'ignore' });
|
|
127
|
+
return true;
|
|
128
|
+
} catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
skillsDir: () => path.join(os.homedir(), '.opencode', 'skills'),
|
|
133
|
+
skillName: SKILL_NAME
|
|
134
|
+
},
|
|
135
|
+
'Cursor': {
|
|
136
|
+
name: 'Cursor',
|
|
137
|
+
detect: () => {
|
|
138
|
+
const homeDir = os.homedir();
|
|
139
|
+
// Check for cursor command or config directory
|
|
140
|
+
if (fs.existsSync(path.join(homeDir, '.cursor'))) return true;
|
|
141
|
+
if (fs.existsSync(path.join(homeDir, 'Library', 'Application Support', 'Cursor'))) return true;
|
|
142
|
+
try {
|
|
143
|
+
execFileSync('which', ['cursor'], { stdio: 'ignore' });
|
|
144
|
+
return true;
|
|
145
|
+
} catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
skillsDir: () => {
|
|
150
|
+
const homeDir = os.homedir();
|
|
151
|
+
// Try common locations
|
|
152
|
+
const locations = [
|
|
153
|
+
path.join(homeDir, '.cursor', 'skills'),
|
|
154
|
+
path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'skills')
|
|
155
|
+
];
|
|
156
|
+
for (const loc of locations) {
|
|
157
|
+
const parent = path.dirname(loc);
|
|
158
|
+
if (fs.existsSync(parent)) return loc;
|
|
159
|
+
}
|
|
160
|
+
return locations[0]; // Default to first
|
|
161
|
+
},
|
|
162
|
+
skillName: SKILL_NAME
|
|
163
|
+
},
|
|
164
|
+
'Windsurf': {
|
|
165
|
+
name: 'Windsurf',
|
|
166
|
+
detect: () => {
|
|
167
|
+
const homeDir = os.homedir();
|
|
168
|
+
// Check for windsurf command or config directory
|
|
169
|
+
if (fs.existsSync(path.join(homeDir, '.windsurf'))) return true;
|
|
170
|
+
try {
|
|
171
|
+
execFileSync('which', ['windsurf'], { stdio: 'ignore' });
|
|
172
|
+
return true;
|
|
173
|
+
} catch {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
skillsDir: () => path.join(os.homedir(), '.windsurf', 'skills'),
|
|
178
|
+
skillName: SKILL_NAME
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
function detectAndInstall() {
|
|
90
183
|
const homeDir = os.homedir();
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
184
|
+
const installedEditors = [];
|
|
185
|
+
const failedEditors = [];
|
|
186
|
+
|
|
187
|
+
console.log('🔍 Detecting AI code editors...\n');
|
|
188
|
+
|
|
189
|
+
// Detect and install for each editor
|
|
190
|
+
for (const [key, editor] of Object.entries(EDITORS)) {
|
|
191
|
+
try {
|
|
192
|
+
if (editor.detect()) {
|
|
193
|
+
console.log(`✓ Found ${editor.name}`);
|
|
194
|
+
|
|
195
|
+
const skillsDir = editor.skillsDir();
|
|
196
|
+
const skillFile = path.join(skillsDir, editor.skillName);
|
|
197
|
+
|
|
198
|
+
// Create skills directory if it doesn't exist
|
|
199
|
+
if (!fs.existsSync(skillsDir)) {
|
|
200
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Check for conflicts with existing files
|
|
204
|
+
if (fs.existsSync(skillFile)) {
|
|
205
|
+
const existingContent = fs.readFileSync(skillFile, 'utf8');
|
|
206
|
+
// Only skip if it's already our skill
|
|
207
|
+
if (existingContent.includes('voicci $ARGUMENTS')) {
|
|
208
|
+
console.log(` ↳ Skill already installed at: ${skillFile}`);
|
|
209
|
+
installedEditors.push({ name: editor.name, path: skillFile, status: 'exists' });
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Write the skill file
|
|
215
|
+
fs.writeFileSync(skillFile, SKILL_CONTENT, 'utf8');
|
|
216
|
+
console.log(` ↳ Installed skill: ${skillFile}`);
|
|
217
|
+
installedEditors.push({ name: editor.name, path: skillFile, status: 'new' });
|
|
218
|
+
}
|
|
219
|
+
} catch (error) {
|
|
220
|
+
failedEditors.push({ name: editor.name, error: error.message });
|
|
221
|
+
}
|
|
99
222
|
}
|
|
100
223
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
224
|
+
// Summary
|
|
225
|
+
console.log('\n' + '═'.repeat(60));
|
|
226
|
+
|
|
227
|
+
if (installedEditors.length > 0) {
|
|
228
|
+
console.log('\n✅ Voicci CLI installed successfully!');
|
|
229
|
+
console.log('\n📦 Command-line tool: voicci');
|
|
230
|
+
console.log('🔧 Skill command: /voicci-audiobook');
|
|
231
|
+
console.log('\n📍 Installed in:');
|
|
232
|
+
installedEditors.forEach(editor => {
|
|
233
|
+
const status = editor.status === 'new' ? '(new)' : '(already installed)';
|
|
234
|
+
console.log(` • ${editor.name} ${status}`);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
console.log('\n💡 Usage:');
|
|
238
|
+
console.log(' 1. Restart your AI code editor');
|
|
239
|
+
console.log(' 2. Use: /voicci-audiobook "search query"');
|
|
240
|
+
console.log(' 3. Or use CLI directly: voicci "your search query"');
|
|
241
|
+
} else {
|
|
242
|
+
console.log('\n⚠️ No supported AI code editors detected');
|
|
243
|
+
console.log('\nSupported editors: Claude Code, OpenCode, Cursor, Windsurf');
|
|
244
|
+
console.log('\n✓ You can still use the CLI: voicci <command>');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (failedEditors.length > 0) {
|
|
248
|
+
console.log('\n⚠️ Failed to install for:');
|
|
249
|
+
failedEditors.forEach(({ name, error }) => {
|
|
250
|
+
console.log(` • ${name}: ${error}`);
|
|
251
|
+
});
|
|
104
252
|
}
|
|
105
253
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
fs.writeFileSync(skillPath, skillContent, { mode: 0o755 });
|
|
109
|
-
|
|
110
|
-
console.log('✅ Voicci CLI installed successfully!');
|
|
111
|
-
console.log('');
|
|
112
|
-
console.log('📦 Command-line tool: voicci');
|
|
113
|
-
console.log('🎯 Claude Code skill: /voicci');
|
|
114
|
-
console.log('');
|
|
115
|
-
console.log('Try it:');
|
|
116
|
-
console.log(' $ voicci --help');
|
|
117
|
-
console.log(' $ claude');
|
|
118
|
-
console.log(' ❯ /voicci Lord of the Rings');
|
|
119
|
-
console.log('');
|
|
120
|
-
console.log('Docs: https://voicci.com/voicci-cli');
|
|
121
|
-
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('⚠️ Warning: Could not install Claude Code skill');
|
|
124
|
-
console.error(' Error:', error.message);
|
|
125
|
-
console.log('');
|
|
126
|
-
console.log('✅ Voicci CLI tool installed successfully!');
|
|
127
|
-
console.log(' Run: voicci --help');
|
|
128
|
-
process.exit(0);
|
|
254
|
+
console.log('\n' + '═'.repeat(60));
|
|
255
|
+
console.log();
|
|
129
256
|
}
|
|
257
|
+
|
|
258
|
+
detectAndInstall();
|