Go to file
Max Nuding 79405cd08c
Update dependencies & version
2024-01-22 17:33:31 +01:00
.nova Saving song infos to DB, refactor logging 2023-04-23 12:46:14 +02:00
src Migrate to Sveltekit 2.0 2024-01-22 17:26:36 +01:00
static Inlined stylesheet, fixed colors 2023-04-26 18:40:06 +02:00
.editorconfig Add toast for error messages, fix #16 2023-04-07 11:55:17 +02:00
.env.EXAMPLE Add oauth token to websocket connection 2023-10-15 19:39:36 +02:00
.eslintignore Initial commit 2023-03-19 17:00:49 +01:00
.eslintrc.cjs Migrate to Svelte 4 2024-01-22 16:26:06 +01:00
.gitignore Fix #26: Scale images to the correct size and use more efficient image formats 2023-06-14 20:37:30 +02:00
.npmrc Initial commit 2023-03-19 17:00:49 +01:00
.prettierignore Improve type safety 2023-04-22 09:28:42 +02:00
.prettierrc Clean up initial state 2023-03-19 17:17:04 +01:00
README.md Add oauth token to websocket connection 2023-10-15 19:39:36 +02:00
apache2.conf.EXAMPLE Fix #33 2023-06-20 15:45:09 +02:00
faviconDescription.json Improve formatting 2023-04-11 16:02:54 +02:00
icon.svg Add icons, fix #5 2023-04-07 16:47:37 +02:00
moshing-mammut.service.EXAMPLE Fix #17 and improve instructions 2023-04-04 12:32:04 +02:00
package-lock.json Update dependencies & version 2024-01-22 17:33:31 +01:00
package.json Update dependencies & version 2024-01-22 17:33:31 +01:00
start.sh.EXAMPLE Fix #17 and improve instructions 2023-04-04 12:32:04 +02:00
svelte.config.js Migrate to Sveltekit 2.0 2024-01-22 17:26:36 +01:00
tsconfig.json Clean up initial state 2023-03-19 17:17:04 +01:00
vite.config.ts Convert and resize avatars to fit the displayed images 2023-05-02 17:31:16 +02:00


License: MIT Release

Moshing Mammut

The fine folks on the metalhead.club Mastodon Server occasionally share like to share what they're currently listening to. Having a quick overview over what is being posted can be a great way to discover new music!

Technical Notes

This is fairly simple from a technical point of view! metalhead.club's local timeline is being watched using the Mastodon Streaming API over a Websocket. Every time a new post arrives, it is checked if it contains any music by checking included hashtags and URLs. A list of tags can be found in the configuration. Additionally, links are vetted if they are music by checking if https://song.link finds info on them.

If a post passes this check it is saved to a SQLite database.

The UI is built using SvelteKit. The initial page is rendered on the server, and works even without Javascript. If Javascript is enabled, new posts are fetched every 10 seconds, but there are plans to switch to Websockets instead. See #10.

The Mastodon Elephant in the Room

So, are you just going to save other peoples posts into your own database?

I'm afraid so, and I'm not particularly happy about this. I've thought about how to do it without and it doesn't look good.

My initial plan was to search for posts and work with the search results, however Mastodon doesn't offer full text search, so this would be limited to work with hashtags. I can see that there are plenty of posts using only descriptions and links without a corresponding hashtag that would be missed. This isn't a great solution.

Another idea was to store only URLs of posts and resolve the content and account information live. This would be better, but I'm still storing post information while also slowing the app down and introduce more code complexity. I'm willing to make this change if people prefer this though.

Additionally, I ended up adding a few things which turned out to be not needed: The tags table (tags are included in the post's content and I don't do anything separately with tags) and accounts.username (s being used for #18) and accounts.avatar_static (has been removed). I will keep these in until the initial wave of feedback arrives, and remove it if no new features required them.

I'll gladly accept any help in coming up with a good solution which doesn't need to store anything at all!

Set Up

This might not be the ideal setup to run this, but here's how I am doing it. Instructions are for running on a Debian or Debian derivative, using Apache as HTTP Proxy. Other setups are possible, but not covered here. By default, NVM is used to install NodeJS, but you can install it any way you want.

This is based on SvelteKit's instructions and How To Deploy Node.js Applications Using Systemd and Nginx

On your server

Install Apache2 if not already installed.

Copy apache2.conf.EXAMPLE and moshing-mammut.service.EXAMPLE to your server.

Set up a user for the app: useradd -mrU moshing-mammut

Switch to your newly created user: su moshing-mammut

Set up NVM:

$ cd
$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh
$ source ~/.nvm/nvm.sh
$ nvm install --lts

Create a directory for the app. This will be called $APP_DIR from now on. I use /home/moshing-mammut/app.

Enter $APP_DIR.

Place package-lock.json and start.sh.EXAMPLE in this directory. Run npm ci --omit dev to install the dependencies.

Rename start.sh.EXAMPLE to start.sh and set the path to your NVM.

If you do not have NVM installed, simply remove the line and make sure your node executable can be found either by specifying the full path or by adding it to your $PATH.

Exit out of your moshing-mammut user shell.

Copy apache2.conf.EXAMPLE to /etc/apache2/sites-available/moshingmammut.conf and replace ServerName with your Domain. If you do not need or want SSL support, remove the whole <IfModule mod_ssl.c> block. If you do, add the path to your SSLCertificateFile and SSLCertificateKeyFile.

Modify DocumentRoot and the two Alias and Directory statements, so that thumbnails and avatars are served directly by apache.

Copy moshing-mammut.service.EXAMPLE to /etc/systemd/system/moshing-mammut.service and set your User, Group, ExecStart and WorkingDirectory accordingly.

On your development machine

Copy .env.EXAMPLE to .env and add your YOUTUBE_API_KEY and ODESLI_API_KEY. To obtain one follow YouTube's guide to create an API key. If YOUTUBE_API_KEY is unset, no playlist will be updated. Also, all YouTube links will be treated as music videos, because the API is the only way to check if a YouTube link leads to music or something else.

If ODESLI_API_KEY is unset, your rate limit to the song.link API will be lower.

Add MASTODON_ACCESS_TOKEN as well, see [Creating our application

](https://docs.joinmastodon.org/client/token/#app) in the Mastodon documentation. read:statuses is the only required scope. An access token will be displayed in your settings. Use that!

There are currently no plans to implement an actual authentication flow.

Run npm run build and copy the output folder, usually build to $APP_DIR on your server.

On your server again

Now, you are ready to start everything up.

Enable the site in Apache2 by running a2ensite moshingmammut.conf.

Create and start the system service by running sudo systemctl enable moshing-mammut.service and then service moshing-mammut start.

Verify that everything is okay with service moshing-mammut status.

The app should now be reachable on http://localhost:3000 or whatever you configured your domain to be!


Favicon is a combination of speaker-line by remix icon and the official Mastodon icon.

It has been mushed together by me, saved as SVG file in icon.svg and turned into a slew of icons by https://realfavicongenerator.net/:

npm install -g cli-real-favicon
real-favicon generate faviconDescription.json faviconData.json static

Other icons: