{"id":36533846,"url":"https://github.com/jdblack/sotd","last_synced_at":"2026-01-12T03:04:33.200Z","repository":{"id":43392889,"uuid":"506899274","full_name":"jdblack/sotd","owner":"jdblack","description":"A song of the day bot written in go for slack","archived":false,"fork":false,"pushed_at":"2023-03-07T16:03:17.000Z","size":162,"stargazers_count":3,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-11T21:49:21.546Z","etag":null,"topics":["bot","golang","slack","sqlite","sqlite3"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdblack.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-24T06:17:36.000Z","updated_at":"2022-08-18T23:38:42.000Z","dependencies_parsed_at":"2024-06-20T00:24:41.235Z","dependency_job_id":null,"html_url":"https://github.com/jdblack/sotd","commit_stats":{"total_commits":138,"total_committers":2,"mean_commits":69.0,"dds":0.06521739130434778,"last_synced_commit":"ebbccd0ef873ef1c5f1b7cf4d5bb40d17b3cc762"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/jdblack/sotd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdblack%2Fsotd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdblack%2Fsotd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdblack%2Fsotd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdblack%2Fsotd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdblack","download_url":"https://codeload.github.com/jdblack/sotd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdblack%2Fsotd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28332872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","golang","slack","sqlite","sqlite3"],"created_at":"2026-01-12T03:04:33.132Z","updated_at":"2026-01-12T03:04:33.188Z","avatar_url":"https://github.com/jdblack.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n![GitHub CI](https://github.com/jdblack/sotd/actions/workflows/testing.yml/badge.svg)\n![GitHub CI](https://github.com/jdblack/sotd/actions/workflows/coverage.yml/badge.svg)\n\n# Song of the day bot\n\nThis project is a Song of the Day Slack Bot that provides daily link from a \nlist of songs to one or more channels.   The bot provides a separate \nplaylist for each channel.   Channels that run out of their private list of\nsongs will backfill from songs that have been previously played in other\nchannels.\n\nThe playlist for each channel is randomized, allowing users to add many of\ntheir favorite songs at one time without hogging the front of the playlist\nqueue. Prolific users are able to swamp out other users,  so it's \nadvisable to encourage many users to participate!\n\n## Usage\n\nInteration with the bot primarily happens via private message. You can send\nthe following commands to the bot to control song of the day for your channel\n\n\n### Bot commands\n-------------------\n\nThis bot only listens for private messaages for security purposes. There is\nalso no need to invite Sotd into any channels for it to work, as it can \npost blindly into channels.\n\n\n\n\n**add CHANNEL URL [OPTIONAL DESCRIPTION]**  - Add a song to a play with optional\ndescription\n\n**delete URL**  - Delete song matching URL\n\n**playlists** - List all running playlists\n\n**load CHANNEL PATH|URL**  - Import a json playlist from an URL.  Imports will be\ncredited to the importer (See Bulk Importing Songs, below)\n\n**stop CHANNEL** - Tell SOTD to remove a playlist for a channel. The songs will be\nsaved for backfill, but the playlist will be gone, gone, gone\n\n**show CHANNEL** - Show the playlist for a given channel\n\n**hello** - Say hello\n\n\n## Crontab\n\nEach channel can be scheduled independently of one another. The pattern is a\nstanadrd cron format (https://en.wikipedia.org/wiki/Cron) with numeric fields\nfor Minute, Hour, Day of Month, Month and Day of week (numeric, sunday being 0)\n\n\n` 00 22 * * 1-5 ` - Play a song at 22:00 UTC (3PM PDT) Mon-Fri  to celebrate the deployment window\n` 00 16 * * 1 ` -  Play a monday morning song every Monday for the SRE Livesite channel \n\nThe main intent is for each channel to set the best time for SOTD for their own\nchannel playlist, but the functiality is there if you want to set your cron up\nfor certain months or days of the month too.  \n\n## Bulk Importing Songs\n\nSongs can be imported over HTTP/S via a json formatted list. The list should have\nthe following structure:\n\n```\n[\n  {\n    \"URL\": \"https://www.youtube.com/watch?v=hQKfAdhXBpA\"\n    \"Description\": \"Kids playing drums in new orleans\"\n  },\n  {\n    \"URL\": \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\",\n    \"Description\": \"Would I be me without this one?\"\n  },\n]\n```\n\nYou can instruct the bot to import the bot to import this list to the playlist of your choice\nby messaging it  `load #your_channel_name https://some.url/here.json`.  Imported songs will\nbe credited to you, so I'd suggest being thoughtful about introducting NSFW songs in your \nwork environment.\n\n\n## Installation\n\nSotd is able source its configuration from either Ini files or environment variables, depending upon\nwhether the deployment is intended for traditional installs or docker. Any configuration value specified\nin the ini config may be set via the environment by setting a key of `SOTD_$section_$key=\"value\"`.  For\nexample, one can turn on event streaming by  running export `SOTD_slack_debug=true` \n\n```\n\n[slack]\n# debug = anything   # Setting debug to any value will turn it on\nbotToken=xoxb-#############-#############-########################\nappToken=xapp-#-###########-#############-################################################################\n```\n\n### Docker Installation\n\nAs mentioned, sotd can be deployed as a container as well, by setting envrionment variables.  For example,\nthis will set up an ephemeral sotd bot\n\n```\n# An example \n# cat \u003e envfile \u003c\u003cEOF\n# SOTD_slack_botToken=xoxb-xxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxx\n# SOTD_slack_appToken=xapp-x-xxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxxx\n# SOTD_database_type=sqlite\n# SOTD_database_path=\"file::memory:?cache=shared\" \n```\n\n\n## Databases\n\nSotd supports both SQLite and MySQL which may be chosen by setting type under\n[Database] to \"sqlite\" or \"mysql\" \n\nSqlite\n--------\n\nThe sqlite connector requires  single argument under the database section, the\npath of the database. A temporary database can be created in memory by setting\na path of \"file::memory:?cache=shared\"\n\n```\n[database]\ntype = \"sqlite\"\npath = \"/var/lib/sotdbot.db\"\n```\n\nOne can also an ephemal version of sotd, perhaps for debugging. Playlists will\nbe lost when the process dies!\n\n```\n[database]\ntype = \"sqlite\"\npath = \"file::memory:?cache=shared\"\n```\n\n\nMysql\n------\n\nThe mysql connector requires 5 options;   host, port, user, pass and db.  \n\n```\n[database]\ntype = \"mysql\"\nuser = \"username\"\nhost = \"mysql-server\"\npass = \"password\"\ndb   = \"database name\"\n```\n\n\nInsecure Options\n---------------\n\nSome options, such as loading playlists from the filesystem or url, have security implications. These options\nare disabled by default but may be reenabled via configuration file\n\n```\n[insecure]\nloading = true  # Allow loading playlists via URL or local filesystem\n```\n\nDesign\n--------\n\n```mermaid\ngraph TD;\n   slack{slack api}\u003c-- event handler --\u003ebot\n   bot-- FromBot\u003cbr /\u003echannel --\u003e controller\n   controller-- funcs  --\u003ejukebox\n   controller-- ToBot\u003cbr /\u003echannel --\u003ebot\n   controller-- funcs  --\u003ebot\n   jukebox --\u003e cron{Cron Scheduler}\n   cron{Cron Scheduler}-- Playset\u003cbr /\u003echannel --\u003econtroller\n```\n\n\n## Dedication\n\nThis project is dedicated to my close friends Belmin, Brandon, Brian, Drew,\nJaysen, Jeff, Jeremy and Jhurani.  You guys mean the world to me and I \nliterally can not wait for the day for our paths to cross again.  Come \nsee me =)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdblack%2Fsotd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdblack%2Fsotd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdblack%2Fsotd/lists"}