do thing, pretty specific to my county but can be changed for other uses!
This commit is contained in:
commit
5d11a276c5
143
.gitignore
vendored
Normal file
143
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-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
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
.output
|
||||||
|
|
||||||
|
# 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 directory
|
||||||
|
.temp
|
||||||
|
|
||||||
|
# Sveltekit cache directory
|
||||||
|
.svelte-kit/
|
||||||
|
|
||||||
|
# vitepress build output
|
||||||
|
**/.vitepress/dist
|
||||||
|
|
||||||
|
# vitepress cache directory
|
||||||
|
**/.vitepress/cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# Firebase cache directory
|
||||||
|
.firebase/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
|
# yarn v3
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# Vite files
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
vite.config.ts.timestamp-*
|
||||||
|
.vite/
|
||||||
222
index.js
Normal file
222
index.js
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
require("dotenv").config({quiet:true})
|
||||||
|
|
||||||
|
const ws = require("ws");
|
||||||
|
// const conn = new ws("wss://saubeo.solutions/demo/rdio-scanner/");
|
||||||
|
const conn = new ws("wss://rosebud-mt.ko4wal.radio")
|
||||||
|
const fs = require("fs");
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const hook = new Discord.WebhookClient({ url: process.env.DISCORD_WEBHOOK_URL });
|
||||||
|
|
||||||
|
const knownTones = {
|
||||||
|
"634.5:706.8": "<@&1531872533119504464>",
|
||||||
|
"601.1:706.8": "<@&1531872550852755596>",
|
||||||
|
}
|
||||||
|
|
||||||
|
// create or empty the temp folder
|
||||||
|
if (!fs.existsSync("./temp")) {
|
||||||
|
fs.mkdirSync("./temp");
|
||||||
|
} else {
|
||||||
|
fs.readdirSync("./temp").forEach((file) => {
|
||||||
|
fs.unlinkSync(`./temp/${file}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build an LFM filter map that enables every talkgroup, in every group,
|
||||||
|
// on every system found in the CFG payload.
|
||||||
|
var globalSystems = {};
|
||||||
|
|
||||||
|
function buildFullLfmFilter(config) {
|
||||||
|
const filter = {};
|
||||||
|
const systems = (config && config.systems) || {};
|
||||||
|
|
||||||
|
for (const sysId of Object.keys(systems)) {
|
||||||
|
const system = systems[sysId];
|
||||||
|
const talkgroups = (system && system.talkgroups) || [];
|
||||||
|
|
||||||
|
filter[system.id] = filter[system.id] || {};
|
||||||
|
globalSystems[system.id] = {};
|
||||||
|
globalSystems[system.id].name = system.label;
|
||||||
|
for (const tg of talkgroups) {
|
||||||
|
const groupId = tg.groupId ?? tg.group ?? tg.tagId ?? 0;
|
||||||
|
filter[system.id][tg.id] = true;
|
||||||
|
globalSystems[system.id][tg.id] = tg;
|
||||||
|
// console.log(tg)
|
||||||
|
}
|
||||||
|
// Print out number of talkgroups for system, and sys name
|
||||||
|
console.log(`System ${system.label} (${system.id}) has ${talkgroups.length} talkgroups.`);
|
||||||
|
}
|
||||||
|
// console.log(JSON.stringify(filter, null, 2));
|
||||||
|
// console.log("Global systems:", JSON.stringify(globalSystems, null, 2));
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper function around twotonedec.py to call it from Node.js and return the result.
|
||||||
|
const { spawn } = require("child_process");
|
||||||
|
|
||||||
|
const decodeTwoTone = (filePath) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// FFMPEG Convert file to wav
|
||||||
|
const wavFilePath = filePath.replace(/\.\w+$/, ".wav");
|
||||||
|
console.log(`Converting ${filePath} to ${wavFilePath} using FFMPEG...`);
|
||||||
|
// unlink the wav file if it already exists
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
console.log("Original:", filePath);
|
||||||
|
console.log("WAV:", wavFilePath);
|
||||||
|
console.log("Absolute:", path.resolve(wavFilePath));
|
||||||
|
console.log("Exists:", fs.existsSync(wavFilePath));
|
||||||
|
if (fs.existsSync(wavFilePath)) {
|
||||||
|
fs.unlinkSync(wavFilePath);
|
||||||
|
}
|
||||||
|
const ffmpegProcess = spawn("ffmpeg", [
|
||||||
|
"-y",
|
||||||
|
"-i", filePath,
|
||||||
|
"-acodec", "pcm_s16le",
|
||||||
|
"-ar", "8000", // or whatever your decoder expects
|
||||||
|
"-ac", "1", // mono if required
|
||||||
|
wavFilePath
|
||||||
|
]);
|
||||||
|
|
||||||
|
ffmpegProcess.on("close", (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
reject(new Error(`FFMPEG process exited with code ${code}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Proceed with Python process only after FFMPEG conversion is successful
|
||||||
|
const pythonProcess = spawn("python", ["twotonedec.py", wavFilePath]);
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
pythonProcess.stdout.on("data", (data) => {
|
||||||
|
result += data.toString();
|
||||||
|
});
|
||||||
|
pythonProcess.stderr.on("data", (data) => {
|
||||||
|
console.error(`stderr: ${data}`);
|
||||||
|
});
|
||||||
|
pythonProcess.on("close", (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
try {
|
||||||
|
result = JSON.parse(result.replace(/'/g, '"'));
|
||||||
|
// Delete the wav file after processing
|
||||||
|
fs.unlink(wavFilePath, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(`Error deleting wav file: ${err}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resolve(result);
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Python process exited with code ${code}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// decodeTwoTone("test2.m4a").then((result) => {
|
||||||
|
// console.log("Two-tone detection result:", result);
|
||||||
|
// }) // Test code
|
||||||
|
|
||||||
|
conn.on("message", (data) => {
|
||||||
|
let msg = data.toString()
|
||||||
|
let parsed = JSON.parse(msg)
|
||||||
|
// console.log("Received message:", parsed);
|
||||||
|
switch(parsed[0]) {
|
||||||
|
case "CFG": // Config RX
|
||||||
|
const config = parsed[1];
|
||||||
|
const lfmFilter = buildFullLfmFilter(config);
|
||||||
|
console.log("Got config from server, sending LFM filter");
|
||||||
|
conn.send(JSON.stringify(["LFM", lfmFilter]));
|
||||||
|
break;
|
||||||
|
case "LFM": // LFM Response
|
||||||
|
if (parsed[1] == true) {
|
||||||
|
console.log("LFM filter accepted by server.");
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
// conn.send(JSON.stringify(["CAL","616","p"]))
|
||||||
|
} else {
|
||||||
|
console.error("LFM filter rejected by server:", parsed[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "LSC": // Listener Count
|
||||||
|
console.log("Listener count:", parsed[1]);
|
||||||
|
break;
|
||||||
|
case "VER": // Ver info
|
||||||
|
console.log(`${parsed[1].branding} RDIO v${parsed[1].version}`)
|
||||||
|
conn.send(JSON.stringify(["CFG"]));
|
||||||
|
break;
|
||||||
|
case "CAL": // New call
|
||||||
|
console.log(`New Call ${globalSystems[parsed[1].system][parsed[1].talkgroup].name} call #${parsed[1].id}`);
|
||||||
|
const tgName = globalSystems[parsed[1].system][parsed[1].talkgroup].name;
|
||||||
|
fs.writeFileSync(`./temp/${parsed[1].audioName}`, Buffer.from(parsed[1].audio.data));
|
||||||
|
decodeTwoTone(`./temp/${parsed[1].audioName}`).then((result) => {
|
||||||
|
console.log(`Two-tone detection result for ${tgName}:`, result);
|
||||||
|
// Two tone result will be array of objects for each detected twotone activation. .detected is array of two frequencies, one for each tone. Create a counter for each pair of frequencies detected. Make a message to send to discord with the tone names, so if 2 copies of RC EMS are sent, send "RC EMS (2x)" instead. For multiple, send "RC EMS (2x), RC Fire (1x)" etc.
|
||||||
|
const toneCounts = {};
|
||||||
|
for (const activation of result) {
|
||||||
|
const detected = activation.detected;
|
||||||
|
const key = `${detected[0]}:${detected[1]}`;
|
||||||
|
if (toneCounts[key]) {
|
||||||
|
toneCounts[key]++;
|
||||||
|
} else {
|
||||||
|
toneCounts[key] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const toneMessages = [];
|
||||||
|
for (const key in toneCounts) {
|
||||||
|
const name = knownTones[key] || key;
|
||||||
|
const count = toneCounts[key];
|
||||||
|
toneMessages.push(count > 1 ? `${name} (${count}x)` : name);
|
||||||
|
}
|
||||||
|
const message = toneMessages.join(", ");
|
||||||
|
console.log(`Two-tone summary for ${tgName}:`, message);
|
||||||
|
hook.send({
|
||||||
|
// Username is tg name
|
||||||
|
username: globalSystems[parsed[1].system][parsed[1].talkgroup].name,
|
||||||
|
content: `${message}`,
|
||||||
|
// Upload audio file
|
||||||
|
files: [{
|
||||||
|
attachment: `./temp/${parsed[1].audioName}`,
|
||||||
|
name: parsed[1].audioName
|
||||||
|
}]
|
||||||
|
}).then(() => {
|
||||||
|
// Delete the audio file after sending to Discord
|
||||||
|
fs.unlink(`./temp/${parsed[1].audioName}`, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(`Error deleting audio file: ${err}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("Unknown message:", JSON.stringify(parsed));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.on("open", () => {
|
||||||
|
console.log("Connected to the server.");
|
||||||
|
conn.send(JSON.stringify(["VER"]))
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.on("close", () => {
|
||||||
|
// Set 3 second timeout to reconnect.
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Connection closed. Reconnecting...");
|
||||||
|
conn = new ws("wss://rosebud-mt.ko4wal.radio");
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.on("error", (err) => {
|
||||||
|
console.error("Connection error:", err);
|
||||||
|
// Close conn, and reconnect after 3 seconds
|
||||||
|
conn.close();
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Reconnecting...");
|
||||||
|
conn = new ws("wss://rosebud-mt.ko4wal.radio");
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
329
package-lock.json
generated
Normal file
329
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
{
|
||||||
|
"name": "rdio-to-discord",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "rdio-to-discord",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"discord.js": "^14.27.0",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
|
"ws": "^8.21.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/builders": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/formatters": "^0.6.2",
|
||||||
|
"@discordjs/util": "^1.2.0",
|
||||||
|
"@sapphire/shapeshift": "^4.0.0",
|
||||||
|
"discord-api-types": "^0.38.40",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"ts-mixer": "^6.0.4",
|
||||||
|
"tslib": "^2.6.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.11.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/collection": {
|
||||||
|
"version": "1.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
|
||||||
|
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/formatters": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"discord-api-types": "^0.38.33"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.11.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/rest": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-wvOylxNYJkwKjctS/Mn5GP1w9r3/rzyH+ThD1JlAca6zEdlHs8QWBBUQJpU5Q+W6DoIj/Ljh1IPlZs7hTU+UAg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/collection": "^2.1.1",
|
||||||
|
"@discordjs/util": "^1.2.0",
|
||||||
|
"@sapphire/async-queue": "^1.5.3",
|
||||||
|
"@sapphire/snowflake": "^3.5.5",
|
||||||
|
"@vladfrangu/async_event_emitter": "^2.4.6",
|
||||||
|
"discord-api-types": "^0.38.50",
|
||||||
|
"magic-bytes.js": "^1.13.0",
|
||||||
|
"tslib": "^2.6.3",
|
||||||
|
"undici": "^6.27.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/util": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"discord-api-types": "^0.38.33"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/ws": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/collection": "^2.1.0",
|
||||||
|
"@discordjs/rest": "^2.5.1",
|
||||||
|
"@discordjs/util": "^1.1.0",
|
||||||
|
"@sapphire/async-queue": "^1.5.2",
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||||
|
"discord-api-types": "^0.38.1",
|
||||||
|
"tslib": "^2.6.2",
|
||||||
|
"ws": "^8.17.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.11.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sapphire/async-queue": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=v14.0.0",
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sapphire/shapeshift": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=v16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sapphire/snowflake": {
|
||||||
|
"version": "3.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.5.tgz",
|
||||||
|
"integrity": "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=v14.0.0",
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "26.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz",
|
||||||
|
"integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~8.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ws": {
|
||||||
|
"version": "8.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||||
|
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vladfrangu/async_event_emitter": {
|
||||||
|
"version": "2.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz",
|
||||||
|
"integrity": "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=v14.0.0",
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/discord-api-types": {
|
||||||
|
"version": "0.38.52",
|
||||||
|
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.52.tgz",
|
||||||
|
"integrity": "sha512-uwe9EKfbjsmgWc2fdFjvDbj+dQqx3lp7wqDCmIha0jInuU+xeQjkCK9tMMn+p7RXfdVQORCInq4cD3U2ymDmyg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"workspaces": [
|
||||||
|
"scripts/actions/documentation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/discord.js": {
|
||||||
|
"version": "14.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.27.0.tgz",
|
||||||
|
"integrity": "sha512-qHbFlFG2N7y3LjPySYsL6A1+BnX6bkTVgo842EX0CqVPk/KTMwZkojPHEXKsQUpWZNyz5BISNHK1cPpQw0+m4A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/builders": "^1.14.1",
|
||||||
|
"@discordjs/collection": "1.5.3",
|
||||||
|
"@discordjs/formatters": "^0.6.2",
|
||||||
|
"@discordjs/rest": "^2.6.2",
|
||||||
|
"@discordjs/util": "^1.2.0",
|
||||||
|
"@discordjs/ws": "^1.2.3",
|
||||||
|
"@sapphire/snowflake": "3.5.5",
|
||||||
|
"discord-api-types": "^0.38.49",
|
||||||
|
"fast-deep-equal": "3.1.3",
|
||||||
|
"lodash.snakecase": "4.1.1",
|
||||||
|
"magic-bytes.js": "^1.13.0",
|
||||||
|
"tslib": "^2.6.3",
|
||||||
|
"undici": "^6.27.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "17.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||||
|
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash": {
|
||||||
|
"version": "4.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||||
|
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.snakecase": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/magic-bytes.js": {
|
||||||
|
"version": "1.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.1.tgz",
|
||||||
|
"integrity": "sha512-x5sn4UX2k5gCWlcfmoFwG4TPie8+dctESyqOBdhB5p6MsgWXdBKGmt9nXPObj/JI50TTL928lc5Yt1WntMn1bw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ts-mixer": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/undici": {
|
||||||
|
"version": "6.28.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
|
||||||
|
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.21.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
|
||||||
|
"integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
package.json
Normal file
18
package.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "rdio-to-discord",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "commonjs",
|
||||||
|
"dependencies": {
|
||||||
|
"discord.js": "^14.27.0",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
|
"ws": "^8.21.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
1170
rdio-docs.md
Normal file
1170
rdio-docs.md
Normal file
File diff suppressed because it is too large
Load diff
8
twotonedec.py
Normal file
8
twotonedec.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from icad_tone_detection import tone_detect
|
||||||
|
|
||||||
|
file_path = sys.argv[1]
|
||||||
|
|
||||||
|
result = tone_detect(file_path)
|
||||||
|
print(result.two_tone_result)
|
||||||
Loading…
Reference in a new issue