Monorepo for Lebkuchen FM project - opinionated YouTube TV-like service with super powers controlled via Discord.
Start by installing dependencies:
yarn install
To build application run:
yarn run build
You can run tests using:
yarn test
To clean up after previous builds before installing dependencies use:
yarn run clean:deps
To run the application you have to connect to MongoDB database.
If you have Docker installed you can use ./scripts/docker_db_local.sh
script to run MongoDB in Docker locally. For more information you can refer to Local MongoDB in Docker documentation section.
Then create .env
file in the root of this project and put desired configuration variables in it (refer to Service > Configuration section of this document for available options).
When that's done you can just start the application:
yarn start
If you want to create local frontend dev server with hot reloading you should use "dev" script from packages/client
:
yarn workspace lebkuchen-fm-client dev
This project is separated into backend service (lebkuchen-fm-service
located in packages/service
) and web client application (lebkuchen-fm-client
located in packages/client
).
For development information specific to modules refer to their Development sections in this document. For more information about managing modules check out yarn workspace docs.
Modules using TypeScript will compile even when there are type checking errors in the code. This allows for fast development iteration. Type checking is done during test
script. For development it's recommended that you use type checker in watch mode:
yarn run test:type-check:watch
This projects consists of these modules:
Core LebkuchenFM Node.js service with MongoDB storage that communicates with clients over WebSockets and REST endpoints.
Configure your instance via environment variables.
MONGODB_URI
- MongoDB connection stringPORT
- port on which the service will be running (automatically injected by cloud providers)LOCALE
- language of the serviceCOMMAND_PROMPT
- command prompt (optional, defaults to/fm
)
YOUTUBE_API_KEY
- YouTube Data API token
DISCORD_CHANNEL_ID
- ID of the Discord channel where the bot is allowed to runDISCORD_CLIENT_ID
- Discord application IDDISCORD_GUILD_ID
- ID of the Discord guild (server) where the bot will operateDISCORD_TOKEN
- token of the Discord bot
DROPBOX_CLIENT_ID
- Dropbox App KeyDROPBOX_SECRET
- Dropbox App SecretDROPBOX_REFRESH_TOKEN
- Dropbox refresh token used for persisting files
LebkuchenFM uses session cookie and/or basic auth with token methods to authorize it's users. Each request to /api/*
endpoint has to be authorized.
Session cookie is set during successful POST
request to /api/auth
endpoint and is generally handled by the web client.
There is no way to register as a new user. Instead LebkuchenFM functions as an invite only system.
When there are no registered users, first login is always correct and creates that account. Every next user has to be created using admin dashboard (/admin
). That way a new account will be created and user is going be able to set the password when they login for the first time.
For external integrations users should use API tokens.
Each user can obtain this token after logging in the web client and requesting GET /api/auth
as mentioned in REST endpoints section of this documentation.
Using this token external tools can integrate with LebkuchenFM by making requests with Authorization: Basic <api-token>
header set.
Socket clients using socket.io can authorize by providing API token during connection like this:
const socket = io({
auth: {
token: "api-token"
}
});
This service communicates with clients mostly using event stream implemented on WebSockets. For possible events check out event data models.
GET /api/auth
Information about currently logged in user.
Response
{
"username": "anton",
"apiToken": "this_users_api_token"
}
POST /api/auth/logout
Logs out currently logged in user.
GET /api/history
History listing containing list of queued songs.
Response
{
"entries": [
{
"date": "2022-05-31T12:46:17.968Z",
"youtubeId": "c6pPAso-y8s"
}
]
}
GET /api/songs
Returns list of all songs in the database sorted by play count (descending).
Response
{
"songs": [
{
"_id": "storage_id",
"name": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"timesPlayed": 1337
}
]
}
POST /api/commands/text
Plain text interface for slash commands.
Body
{
"text": "/fm help"
}
Response
{
"textResponse": "Command response in plain text format"
}
GET /api/users
List of all registered users.
Response
{
"users": [
{
"name": "anton",
"creationDate": "2022-05-31T19:59:05.879Z",
"lastLoggedIn": "2022-05-31T20:01:17.072Z"
}
]
}
GET /api/x-sounds
Returns list of all XSounds in the database.
Response
{
"sounds": [
{
"_id": "storage_id",
"name": "example sound",
"url": "https://example.com/example_sound.wav",
"tags": ["tag1", "tag2"],
"timesPlayed": 6
}
]
}
GET /api/x-sounds?tag=example-tag
Returns a filtered list of XSounds containing given tag in the database.
Response
{
"sounds": [
{
"_id": "storage_id",
"name": "example sound",
"url": "https://example.com/example_sound.wav",
"tags": ["example-tag"],
"timesPlayed": 6
}
]
}
POST /api/x-sounds
Adds new sound file to XSounds database.
Request
Requires content type to be multipart/form-data
with fields:
soundName
: name of the sound to be added (like "cool sound")tags
(optional): comma separated list of tags (like "tag1, tag2, tag3")soundFile
: sound File ideally in mp3 or wav format
Response
{
"_id": "storage_id",
"name": "my new sound",
"url": "https://example.com/example_sound.wav",
"timesPlayed": 0
}
GET /api/x-sounds/tags
Returns list of all unique XSounds tags in database.
Response
{
"tags": [
"example tag",
"another tag"
]
}
Web client for the application. Communicates with the service via WebSocket event stream.
Running yarn run dev
runs the application in development mode with hot reload on file change. This version of application won't connect to the service.
Running yarn run build
builds the application in production mode.
Scripts related to maintenance of the service.
Helper script scripts/fm.sh
is available for local development purposes. By default it sends a command to a local development server.
Example commands:
> fm.sh "/fm resume"
> fm.sh "/fm q dQw4w9WgXcQ"
> fm.sh "/fm x alert"
Alternatively you can run it as an yarn command from the root of the project:
> yarn run fm "/fm resume"
> yarn run fm "/fm q dQw4w9WgXcQ"
> yarn run fm "/fm x alert"
Helper script scripts/docker_db_local.sh
runs MongoDB and binds ports for local development.
To stop container run scripts/docker_db_local.sh stop
.
You can also run this app via Docker Compose. It has MongoDB already configured. Just pass other necessary config variables.
docker compose up --build
This project is licensed under the MIT license.