Initial commit
All checks were successful
NPM Audit Check / Check NPM audit (push) Successful in -2m13s
All checks were successful
NPM Audit Check / Check NPM audit (push) Successful in -2m13s
This commit is contained in:
commit
4a260f112f
27
.github/workflows/npm-audit.yml
vendored
Normal file
27
.github/workflows/npm-audit.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: NPM Audit Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '15 16 * * 5'
|
||||
|
||||
jobs:
|
||||
|
||||
npm_audit:
|
||||
name: Check NPM audit
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: true
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: https://github.com/actions/checkout@v4
|
||||
|
||||
- name: NPM Audit
|
||||
run: npm audit
|
104
.gitignore
vendored
Normal file
104
.gitignore
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
# 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/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# 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 variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
|
||||
# custom .gitignore
|
||||
config/config.json5
|
||||
distribution/
|
||||
.env
|
12
README.md
Normal file
12
README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# morning-report
|
||||
|
||||
randomly generate a radio show-style weather report according to a flexible config file.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
npm install
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
118
config/config.example.json5
Normal file
118
config/config.example.json5
Normal file
@ -0,0 +1,118 @@
|
||||
{
|
||||
"programs": [
|
||||
[
|
||||
"intro music",
|
||||
"intro",
|
||||
"hi's and low's",
|
||||
"notable weather",
|
||||
"signoff"
|
||||
]
|
||||
],
|
||||
"segments": {
|
||||
"intro": [
|
||||
"intro 1",
|
||||
"intro 2"
|
||||
],
|
||||
"hi's and low's": [
|
||||
"hilo 1",
|
||||
"hilo 2"
|
||||
],
|
||||
"notable weather": [
|
||||
"rain 1",
|
||||
"rain 2",
|
||||
"storm 1",
|
||||
"storm 2",
|
||||
"snow 1",
|
||||
"hail 1"
|
||||
],
|
||||
"signoff": [
|
||||
"signoff 1",
|
||||
"signoff 2"
|
||||
]
|
||||
},
|
||||
"sequences": {
|
||||
"intro music": {
|
||||
"tracks": [
|
||||
"audio/intro_music.flac"
|
||||
]
|
||||
},
|
||||
"intro 1": {
|
||||
"tracks": [
|
||||
"audio/intro_01.flac"
|
||||
]
|
||||
},
|
||||
"intro 2": {
|
||||
"tracks": [
|
||||
"audio/intro_02.flac"
|
||||
]
|
||||
},
|
||||
"hilo 1": {
|
||||
"tracks": [
|
||||
"audio/hi_01.flac",
|
||||
"%cory hi",
|
||||
"audio/lo_01.flac",
|
||||
"%cory lo"
|
||||
]
|
||||
},
|
||||
"hilo 2": {
|
||||
"tracks": [
|
||||
"audio/hi_02.flac",
|
||||
"%cory hi",
|
||||
"audio/lo_02.flac",
|
||||
"%cory lo"
|
||||
]
|
||||
},
|
||||
"rain 1": {
|
||||
"condition": "weather == rain",
|
||||
"tracks": [
|
||||
"audio/rain1.flac"
|
||||
]
|
||||
},
|
||||
"rain 2": {
|
||||
"condition": "weather == rain",
|
||||
"tracks": [
|
||||
"audio/rain2.flac"
|
||||
]
|
||||
},
|
||||
"storm 1": {
|
||||
"condition": "weather == storm",
|
||||
"tracks": [
|
||||
"audio/storm1.flac"
|
||||
]
|
||||
},
|
||||
"storm 2": {
|
||||
"condition": "weather == storm",
|
||||
"tracks": [
|
||||
"audio/storm2.flac"
|
||||
]
|
||||
},
|
||||
"snow 1": {
|
||||
"condition": "weather == snow",
|
||||
"tracks": [
|
||||
"audio/snow1.flac"
|
||||
]
|
||||
},
|
||||
"hail 1": {
|
||||
"condition": "weather == hail",
|
||||
"tracks": [
|
||||
"audio/hail1.flac"
|
||||
]
|
||||
},
|
||||
"signoff 1": {
|
||||
"tracks": [
|
||||
"audio/signoff_01.flac"
|
||||
]
|
||||
},
|
||||
"signoff 2": {
|
||||
"tracks": [
|
||||
"audio/signoff_02.flac"
|
||||
]
|
||||
}
|
||||
},
|
||||
"voices": {
|
||||
"cory": {
|
||||
"directory": "audio/voice/cory/",
|
||||
"extension": "flac"
|
||||
}
|
||||
}
|
||||
}
|
115
package-lock.json
generated
Normal file
115
package-lock.json
generated
Normal file
@ -0,0 +1,115 @@
|
||||
{
|
||||
"name": "morning-report",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "morning-report",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json5": "2.2.3",
|
||||
"openweathermap-ts": "1.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "24.3.0",
|
||||
"typescript": "5.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
|
||||
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/openweathermap-ts": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/openweathermap-ts/-/openweathermap-ts-1.2.10.tgz",
|
||||
"integrity": "sha512-Zckv2aXN8ENSeAeroces2jJciLWb6aLNXEmvG6pmF+BcIMw2kwRo6++/AKUNoU5suOp47UWA6lllDV0TNm//OA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
|
||||
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
package.json
Normal file
34
package.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "morning-report",
|
||||
"version": "0.0.1",
|
||||
"description": "Procedurally generates a radio weather report",
|
||||
"keywords": [
|
||||
"weather",
|
||||
"radio",
|
||||
"audio"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.sanin.dev:3689/corysanin/morning-report.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Cory Sanin",
|
||||
"email": "corysanin@outlook.com",
|
||||
"url": "https://sanin.dev/"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "distribution/index.js",
|
||||
"scripts": {
|
||||
"build": "npx tsc",
|
||||
"start": "node distribution/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": "2.2.3",
|
||||
"openweathermap-ts": "1.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "5.9.2",
|
||||
"@types/node": "24.3.0"
|
||||
}
|
||||
}
|
23
src/index.ts
Normal file
23
src/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import path from 'path';
|
||||
import fsp from 'fs/promises';
|
||||
import json5 from 'json5';
|
||||
import Sequencer from './sequencer.js';
|
||||
import type {Programs, Segments, Sequences} from './sequencer.js';
|
||||
import type { Voices } from './voice.js';
|
||||
|
||||
|
||||
interface Config {
|
||||
programs: Programs,
|
||||
segments: Segments,
|
||||
sequences: Sequences,
|
||||
voices: Voices
|
||||
}
|
||||
|
||||
console.log('morning-report\nCory Sanin 2025\n');
|
||||
|
||||
const config: Config = json5.parse(await fsp.readFile(process.env['CONFIG'] || path.join('config', 'config.json5'), { encoding: 'utf-8' }));
|
||||
const sequence = Sequencer(config);
|
||||
console.log(sequence.join('\n'));
|
||||
|
||||
|
||||
export type { Config };
|
54
src/sequencer.ts
Normal file
54
src/sequencer.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import type { Config } from './index.js';
|
||||
|
||||
type SegmentName = string;
|
||||
type SequenceName = string;
|
||||
type Programs = SegmentName[][];
|
||||
type Segments = { [segment: SegmentName]: SequenceName[] };
|
||||
type Sequence = {
|
||||
condition?: string;
|
||||
tracks: string[];
|
||||
}
|
||||
type Sequences = { [sequence: SequenceName]: Sequence };
|
||||
|
||||
let config: Config = null;
|
||||
|
||||
function selectOne<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
function conditionIsMet(condition: string | undefined = undefined): boolean {
|
||||
if (typeof condition !== 'string') {
|
||||
return true;
|
||||
}
|
||||
// TODO: parse condition, return bool
|
||||
return false;
|
||||
}
|
||||
|
||||
function processSequence(sequence: Sequence): string[] {
|
||||
const tracks = sequence.tracks;
|
||||
// TODO: process voice macros
|
||||
return tracks;
|
||||
}
|
||||
|
||||
function processSegment(segment: SegmentName): string[] {
|
||||
if (!(segment in config.segments)) {
|
||||
return processSequence(config.sequences[segment]);
|
||||
}
|
||||
const potentialSequences: SequenceName[] = config.segments[segment].filter(s => conditionIsMet(config.sequences[s].condition));
|
||||
if (potentialSequences.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return processSequence(config.sequences[selectOne(potentialSequences)]);
|
||||
}
|
||||
|
||||
function Sequencer(conf: Config): string[] {
|
||||
config = conf;
|
||||
const sequence: string[] = [];
|
||||
const program: SegmentName[] = selectOne(conf.programs);
|
||||
program.forEach(segment => sequence.push(...processSegment(segment)));
|
||||
return sequence;
|
||||
}
|
||||
|
||||
export default Sequencer;
|
||||
export { Sequencer };
|
||||
export type { SegmentName, SequenceName, Programs, Segments, Sequence, Sequences };
|
0
src/stitcher.ts
Normal file
0
src/stitcher.ts
Normal file
10
src/voice.ts
Normal file
10
src/voice.ts
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
interface Voice {
|
||||
directory: string;
|
||||
extension: string;
|
||||
}
|
||||
|
||||
type Voices = { [name: string]: Voice };
|
||||
|
||||
export type { Voice, Voices };
|
0
src/weather.ts
Normal file
0
src/weather.ts
Normal file
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "NodeNext",
|
||||
"target": "ESNext",
|
||||
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "node16",
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./distribution"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["**/*.spec.ts"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user