Browse by type
xdccJS is a complete implementation of the XDCC protocol for nodejs.
It can also be used as a command-line downloader !
- Batch downloads : 1-3, 5, 32-35, 101
- Resume file and auto-retry
- Pipes!
- Passive DCC
- Check advanced examples and see what else you can do
There's three different way to import/require xdccJS depending on which environment it is running:
const XDCC = require('xdccjs')
const xdccJS = new XDCC.default({/*..options..*/})
import XDCC from 'xdccjs'
const xdccJS = new XDCC.default({/*..options..*/})
import XDCC from 'xdccjs'
const xdccJS = new XDCC({/*..options..*/})
const XDCC = require('xdccjs')
const xdccJS = new XDCC.default({
host: 'irc.server.net',
port: 6667,
chan: ['#welcome', '#fansub'],
nickname: 'Leon',
path: '/home/leon/downloads'
})
xdccJS.on('ready', () => {
xdccJS.download('XDCC|BOT_RED', 5)
xdccJS.download('XDCC|BOT_GREEN', '1-3, 55, 100-200')
xdccJS.download('XDCC|BOT_BLUE', [12, 7, 10, 20])
xdccJS.download('XDCC|BOT_ALPHA', ['5', '6'])
})
Every parameter is optional, except for host.
const opts = {
host: 'irc.server.net', // IRC hostname - required
port: 6660, // IRC port - default: 6667
tls: {
enable: true, // Enable TLS Support - default: false
rejectUnauthorized: true, // Reject self-signed certificates - default: false
},
nickname: 'ItsMeJiPaix', // Nickname - default: xdccJS + random
nickServ: 'complex_password', // Your NickServ password (no spaces) - default: undefined (disabled)
chan: ['#candy', '#fruits'], // Array of channels - default : [ ] (no chan)
path: 'downloads', // Download path or 'false' - default: false (which enables piping)
retry: 2, // Nb of retries before skip - default: 1
timeout: 50, // Nb of seconds before a download is considered timed out - default: 30
verbose: true, // Display download progress and jobs status - default: false
randomizeNick: false, // Add random numbers at end of nickname - default: true
passivePort: [5000, 5001, 5002], // Array of port(s) to use with Passive DCC - default: [5001]
botNameMatch: false, // Block downloads if the bot's name does not match the request - default: true
throttle: 500, // Throttle download speed to n KiB/s - default: undefined (disabled)
queue: /soMething(.*)maTching/g // - default: undefined (disabled)
// ^ Regex matching the bot's message when you're request is moved to a queue
}
xdccJS.config( parameters? : object ) change parameters during runtime
If there's a file downloadingthrottleandpassivePortwon't be applied until the next download
xdccJS.config({
passivePort: [5000, 5001, 5002],
throttle: 800,
nickname: 'TrustMe',
chan: ['#candy', '#fruits'],
path: 'download/subfolder',
botNameMatch: false,
retry: 5,
timeout: 50,
verbose: false,
randomizeNick: true,
queue: /soMething(.*)maTching/g
})
xdccJS.download( bot : string, packets : string | number | number[] | string[], options?: { ipv6?: boolean ** throttle?: number } )
download()is asynchronous and returns aJob
optionsare optional, per joboptions.ipv6parameter is only required when if a bot's is ipv6 AND uses passive DCC
xdccJS.on('ready', async () => {
const blue = await xdccJS.download('XDCC|BLUE', '1-3, 8, 55')
const yellow = await xdccJS.download('XDCC|YELLOW', 4)
const red = await xdccJS.download('XDCC|RED', [12, 7, 10, 20])
const purple = await xdccJS.download('XDCC|PURPLE', ['1', '3', '10', '20'])
})
xdccJS will timeout any request after a certain amount of time when no file is sent (see Options.timeout), Which is exactly what happens when a bot puts you into queue.
To avoid this behavior you need to provide a regex matching the bot "queue message".
If you are clueless about regexes try regexlearn.com interactive tutorial.
const opts = {
host: 'irc.server.com',
timeout: 20 // defaut is 30
queue: /request(.*)queued(.*)\d+\/\d+$/gi
//=> excepted bot queue message: "Your request has been queued: position x/x"
}
const xdccJS = new XDCC(opts)
xdccJS.on('ready', async () =>{
const queued = await xdccJS.download('BOT_WITH_LARGE_QUEUE', '1-5')
//=> if the bot sends a message matching the regex, download won't fail
})
Jobs are download() instances which are tied to the target nickname.
calling download() multiple times for the same target will update current job.
xdccJS.on('ready', async () => {
// jobs are automatically updated
const botA_1 = await xdccJS.download('BOT-A', 1)
const botA_2 = await xdccJS.download('BOT-A', 2)
const botA_3 = await xdccJS.download('BOT-A', 3)
// botA_1 === botA_2 === botA_3
// but each "target" has its own job
const botB_1 = await xdccJS.download('DIFFERENT_TARGET', 4)
// botA_1 !== botB_1
// once a job's done, its lifetime ends
botA_1.on('done', async () => {
const botA_5 = await xdccJS.download('BOT-A', 5)
// botA_1 !== botA_5
})
// Job options are overwritable
await xdccJS.download('BOT-B', 1, { throttle: 500 })
await xdccJS.download('BOT-B', 2, { throttle: 1000 })
// => Both packets, 1 and 2, will be throttled at 1000 (latest)
})
xdccJS.jobs( bot : string | undefined )
// find job by botname
const job = await xdccJS.jobs('bot-name')
// retrieve all jobs at once
const arrayOfJobs = await xdccJS.jobs()
js
let status = job1.show()
let isdone = job1.isDone()
console.log(status)
//=> { name: 'a-bot', queue: [98], now: 62, success: ['file.txt'], failed: [50] }
console.log(isdone)
//=> falsejs
job2.cancel()Events to track progress (see events documentation) ```js job.on('downloaded', (fileInfo) => { //=> a file has been downloaded })
job.on('done', () => { //=> job has finished downloading all requested packages })
// more below.. ```
Most events are accessible both from xdccJS or a Job scope
FYI: those examples are for the sake of showing xdccJS capabilities, if you need download status to be displayed in a nice way just start xdccJS with parameter verbose = true
[xdccJS].on( 'ready' ) : xdccJS is ready to download -
js xdccJS.on('ready', async () => { // download() here })[xdccJS | Job].on( 'downloading' ) : Data is being received (a file is downloading) -``js xdccJS.on('downloading', (fileInfo, received, percentage, eta) => { console.log(fileInfo) //=> { file: 'filename.pdf', filePath: '/path/to/filename.pdf', length: 5844849 } console.log(downloading: '${fileInfo.file}'`) //=> downloading: 'your file.pdf' })
job.on('downloading', (fileInfo, received, percentage, eta) => {
console.log(`${percentage}% - ${eta} ms remaining`) //=> 10.55% - 153500 ms remaining
})
```
[xdccJS | Job].on( 'downloaded' ) : A file successfully downloaded - ```js xdccJS.on('downloaded', (fileInfo) => { console.log(fileInfo.filePath) //=> /home/user/xdccJS/downloads/myfile.pdf })
job.on('downloaded', (fileInfo) => {
console.log('Job1 has downloaded:' + fileInfo.filePath)
//=> Job1 has downloaded: /home/user/xdccJS/downloads/myfile.pdf
console.log(fileInfo)
//=> { file: 'filename.pdf', filePath: '/home/user/xdccJS/downloads/myfile.pdf', length: 5844849 }
})
```
[xdccJS | Job].on( 'done' ) : A job has no remaining package in queue - ```js xdccJS.on('done', (job) => { console.log(job.show()) //=> { name: 'a-bot', queue: [98], now: 62, success: ['file.txt'], failed: [50] } })
job.on('done', (job) => {
console.log('Job2 is done!')
console.log(job.show())
//=> { name: 'a-bot', queue: [98], now: 62, success: ['file.txt'], failed: [50] }
})
```
[xdccJS | Job].on( 'pipe' ) : A pipe is available (see pipe documentation) - ```js xdccJS.on('pipe', (stream, fileInfo) => { stream.pipe(somewhere) console.log(fileInfo) //=> { file: 'filename.pdf', filePath: 'pipe', length: 5844849 } })
job.on('pipe', (stream, fileInfo) => {
stream.pipe(somewhere)
console.log(fileInfo)
//=> { file: 'filename.pdf', filePath: 'pipe', length: 5844849 }
})
```
[xdccJS].on( 'error' ) : Connection Errors
-js xdccJS.on('error', (err) => { err instanceof Error //=> true console.error(err.message) //=> UNREACHABLE HOST 1.1.1.1:6667 })[Job].on( 'error' ) : Job interrupted/canceled or connexion with bot unreachable
-js job.on('error', (message, fileInfo) => { console.error(message) //=> timeout: no response from XDCC|BLUE console.log(fileInfo) //=> { file: 'filename.pdf', filePath: 'pipe', length: 5844849 } })[Job].on( 'cancel' ) : Job canceled by user
-js job.on('cancel', (message) => { console.error(message) //=> "cancelled by user" })[xdccJS].on( 'debug' ) : debug message
-js xdccJS.on('debug', (message) => { console.info(message) })
In order to use pipes xdccJS need to be initialized with path option set to false
// This example will start vlc.exe then play the video while it's downloading.
const opts = {
host: 'irc.server.net',
path: false,
}
const xdccJS = new XDCC(opts)
// Start VLC
const { spawn } = require('child_process')
const vlcPath = path.normalize('C:\\Program Files\\VideoLAN\\VLC\\vlc.exe')
const vlc = spawn(vlcPath, ['-'])
xdccJS.on('ready', async () => {
const Job = await xdccJS.download('bot', 155)
// send data to VLC that plays the file
Job.on('pipe', stream => {
stream.pipe(vlc.stdin)
})
})
// event triggered when all jobs are done.
xdccJS.on('can-quit', () => {
xdccJS.quit() // this is how you disconnect from IRC
})
@kiwiirc/irc-framework is embed into xdccJS.
Check their client API documentation
xdccJS.on('ready', () => {
// change nickname
xdccJS.changeNick('new-nickname')
// listen to kick events
xdccJS.on('kick', (info) => {
//=> do something..
})
})
An extended version of this example is available here
npm install xdccjs -g
``` -V, --version output the version number -h, --host IRC server hostname - required --port IRC server port - default: 6667 -n, --nickname Your nickname - default: xdccJS --no-randomize Disable nickname randomization - default: randomize -c, --channel Channel(s) to joi
browse all types & interfaces →
$ claude mcp add xdccJS \
-- python -m otcore.mcp_server <graph>