Published: Dec 26, 2024 by Isaac Johnson
About a year ago I demo’ed NoiseDash which is a simply white noise generator (project page). I recently found another Noise Generator that is similar, but basically marries some ‘channels’ of lo-fi YouTube beats with an overlay of noise generators. We’ll checkout NextBeats and how we can use it and even add our own video(s) to the mix.
What about removing music? Fast Music Remover is a great way to remove some background noise or music in a dockerized app. The backend is based on python and while not the fastest, it does do the job. We’ll launch that into Kubernetes and give it a go on some of my older YouTube videos.
Next Beats
MariusHosting clued me into this back in November and thus it got on my To-Do list to checkout.
The portainer setup he used was:
services:
nextbeats:
image: peppershade/nextbeats
container_name: NextBeats
healthcheck:
test: ["CMD-SHELL", "nc -z 127.0.0.1 3000 || exit 1"]
interval: 10s
timeout: 5s
retries: 3
start_period: 90s
ports:
- 6431:3000
restart: on-failure:5
While the source repo doesn’t include an image, it would seem the dockerhub image from peppershade is someone’s build.
Call me paranoid, but I’m not as keen on using images not from the author.
Building our own image
I’ll clone
builder@builder-T100:~$ git clone https://github.com/btahir/next-beats.git
Cloning into 'next-beats'...
remote: Enumerating objects: 239, done.
remote: Counting objects: 100% (131/131), done.
remote: Compressing objects: 100% (95/95), done.
remote: Total 239 (delta 69), reused 88 (delta 34), pack-reused 108 (from 1)
Receiving objects: 100% (239/239), 40.31 MiB | 22.62 MiB/s, done.
Resolving deltas: 100% (99/99), done.
builder@builder-T100:~$ cd next-beats/
Then build
[+] Building 51.6s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 382B 0.0s
=> [internal] load metadata for docker.io/library/node:20-alpine 1.1s
=> [auth] library/node:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 171B 0.0s
=> [1/6] FROM docker.io/library/node:20-alpine@sha256:426f843809ae05f324883afceebaa2b9cab9cb697097dbb 2.7s
=> => resolve docker.io/library/node:20-alpine@sha256:426f843809ae05f324883afceebaa2b9cab9cb697097dbb 0.0s
=> => sha256:426f843809ae05f324883afceebaa2b9cab9cb697097dbb1a2a7a41c5701de72 7.67kB / 7.67kB 0.0s
=> => sha256:effc1ee6b93c4db0aab5729f3bc25d9df841e9b88ec3c4683d5a948a37553244 1.72kB / 1.72kB 0.0s
=> => sha256:2215267afb33d93392d8d16b41c461a569bf52a442e5af4c4add1371b73f26e3 6.18kB / 6.18kB 0.0s
=> => sha256:38a8310d387e375e0ec6fabe047a9149e8eb214073db9f461fee6251fd936a75 3.64MB / 3.64MB 0.3s
=> => sha256:65052e355180ad17acd4b61613338090c587b931124cd2946b9dcf0e945b76cb 42.54MB / 42.54MB 1.1s
=> => sha256:9cf3157062e6e87bb84921361434e0c930e8f73584eb06114cf7563178355253 1.26MB / 1.26MB 0.4s
=> => extracting sha256:38a8310d387e375e0ec6fabe047a9149e8eb214073db9f461fee6251fd936a75 0.2s
=> => sha256:dcfb660a4e70b11e73b64689666db5db05706d6d6a9bb950d9fea8593712af3c 446B / 446B 0.4s
=> => extracting sha256:65052e355180ad17acd4b61613338090c587b931124cd2946b9dcf0e945b76cb 1.0s
=> => extracting sha256:9cf3157062e6e87bb84921361434e0c930e8f73584eb06114cf7563178355253 0.1s
=> => extracting sha256:dcfb660a4e70b11e73b64689666db5db05706d6d6a9bb950d9fea8593712af3c 0.0s
=> [internal] load build context 0.1s
=> => transferring context: 7.41MB 0.1s
=> [2/6] WORKDIR /app 0.6s
=> [3/6] COPY package*.json ./ 0.0s
=> [4/6] RUN npm install 12.3s
=> [5/6] COPY . . 0.1s
=> [6/6] RUN npm run build 29.3s
=> exporting to image 5.4s
=> => exporting layers 5.4s
=> => writing image sha256:62c9ebc3e072477887e3d1610f1645fe680a2253bbb6c0e49269025be044d8d5 0.0s
=> => naming to harbor.freshbrewed.science/freshbrewedprivate/nextbeats:latest 0.0s
Here is where I love the Nexterm we installed a week ago as it proves quite handy
I can then push to my Harbor CR
builder@builder-T100:~/next-beats$ docker push harbor.freshbrewed.science/freshbrewedprivate/nextbeats:latest
The push refers to repository [harbor.freshbrewed.science/freshbrewedprivate/nextbeats]
255da4eecdc5: Pushed
e206a4b8143b: Pushed
64c3ab40a1db: Pushed
896f9312bfab: Pushed
416cf80a51ee: Pushed
9fd30ff9d315: Pushed
875b8fb676b2: Pushed
8c0ba6a3f014: Pushed
3e01818d79cd: Pushed
latest: digest: sha256:dd5116f3ba681b99dad085abb3b0203c2e7708a756a67c176be844aa1f65b3bb size: 2209
builder@builder-T100:~/next-beats$
I can have Gemini Code Assist help turn that into a YAML Manifest for me
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextbeats
spec:
replicas: 1
selector:
matchLabels:
app: nextbeats
template:
metadata:
labels:
app: nextbeats
spec:
containers:
- name: nextbeats
image: harbor.freshbrewed.science/freshbrewedprivate/nextbeats:latest # Using your built image
ports:
- containerPort: 3000
livenessProbe:
exec:
command: ["nc", "-z", "localhost", "3000"]
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe: # Added readinessProbe for better control
exec:
command: ["nc", "-z", "localhost", "3000"]
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
imagePullSecrets:
- name: myharborreg
---
apiVersion: v1
kind: Service
metadata:
name: nextbeats
spec:
selector:
app: nextbeats
ports:
- protocol: TCP
port: 6431 # External port
targetPort: 3000 # Port the container exposes
type: ClusterIP # Or NodePort, depending on your needs
Then apply it
$ kubectl apply -f ./lofi.yaml
deployment.apps/nextbeats created
service/nextbeats created
I ran for a bit but it took a bit over 2m to come up to running
Every 2.0s: kubectl get pods -l app=nextbeats LuiGi: Wed Dec 18 19:18:58 2024
NAME READY STATUS RESTARTS AGE
nextbeats-675f7d7557-ck4hm 1/1 Running 0 2m39s
I did a port-forward
$ kubectl port-forward svc/nextbeats 6431:6431
Forwarding from 127.0.0.1:6431 -> 3000
Forwarding from [::1]:6431 -> 3000
Handling connection for 6431
Handling connection for 6431
Handling connection for 6431
And found a pretty nice interface. Ironically the loaded YouTube was one I had listened to before and I was listening to a very similar channel as I was writing this
As I’m somewhere loud and am using my phone, I think I need to create an ingress so I can test on the mobile.
I’ll fire up a quick Azure DNS A Record
$ az account set --subscription "Pay-As-You-Go" && az network dns record-set a add-record -g idjdnsrg -z tpk.pw -a 75.73.224.240 -n nextbeats
{
"ARecords": [
{
"ipv4Address": "75.73.224.240"
}
],
"TTL": 3600,
"etag": "62262f35-5453-45ed-a21a-73428e39b125",
"fqdn": "nextbeats.tpk.pw.",
"id": "/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjdnsrg/providers/Microsoft.Network/dnszones/tpk.pw/A/nextbeats",
"name": "nextbeats",
"provisioningState": "Succeeded",
"resourceGroup": "idjdnsrg",
"targetResource": {},
"trafficManagementProfile": {},
"type": "Microsoft.Network/dnszones/A"
}
Then we can create an Ingress YAML to use it
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: azuredns-tpkpw
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.org/websocket-services: nextbeats
name: nextbeatsingress
spec:
rules:
- host: nextbeats.tpk.pw
http:
paths:
- backend:
service:
name: nextbeats
port:
number: 6431
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- nextbeats.tpk.pw
secretName: mynextbeats-tls
I can then apply
$ kubectl apply -f ./nextbeats.ingress.yaml
ingress.networking.k8s.io/nextbeatsingress created
And wait for the cert to be satisified
$ kubectl get cert mynextbeats-tls
NAME READY SECRET AGE
mynextbeats-tls True mynextbeats-tls 84s
It loaded just great
and we can use the ambience sliders to add extra noise like rain or wind to the YouTube video.
I can add a new Channel (such as the one I was listening to)
It now shows as Channel 7
I presently am not getting any adverts but I don’t know if its how the video is pulled or if YouTube just picked up my account (which has YouTube premium).
Music Remover
On the topic of music, Marius turned me on to Fast Music Remover
From the Github page, we can see it’s a pretty straightforward docker app
docker run -p 8080:8080 ghcr.io/omeryusufyagci/fast-music-remover:latest
I can make that a Kubernetes manifest with a Deployment and Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fast-music-remover
spec:
replicas: 1
selector:
matchLabels:
app: fast-music-remover
template:
metadata:
labels:
app: fast-music-remover
spec:
containers:
- name: fast-music-remover
image: ghcr.io/omeryusufyagci/fast-music-remover:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: fast-music-remover-service
spec:
type: ClusterIP
selector:
app: fast-music-remover
ports:
- protocol: TCP
port: 8080
targetPort: 8080
Then apply
$ kubectl apply -f ../musicremover.yaml
deployment.apps/fast-music-remover created
service/fast-music-remover-service created
Let’s port-forward
$ kubectl port-forward svc/fast-music-remover-service 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
And we can see it running
Let’s take a video of mine from a couple years back which has music in there.
It’s taking a fair amount of time but seems to be processing
The resulting video didn’t seem to play
and I could see some errors in my forwarding output
$ kubectl port-forward svc/fast-music-remover-service 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
E1220 05:50:22.626626 54939 portforward.go:381] error copying from remote stream to local connection: readfrom tcp6 [::1]:8080->[::1]:57962: write tcp6 [::1]:8080->[::1]:57962: write: broken pipe
Handling connection for 8080
E1220 05:50:52.628170 54939 portforward.go:347] error creating error stream for port 8080 -> 8080: Timeout occurred
Handling connection for 8080
E1220 05:51:22.945613 54939 portforward.go:347] error creating error stream for port 8080 -> 8080: Timeout occurred
Handling connection for 8080
It seems to get stuck
I’m going to move on to exposing via the ingress to see if it helps
$ gcloud dns --project=myanthosproject2 record-sets create fms.steeped.space --zone="steepedspace" --type="A" --ttl="300" --rrdatas="75.73.224.240"
NAME TYPE TTL DATA
fms.steeped.space. A 300 75.73.224.240
I’ll make an ingress YAML
$ cat ./fastmusic.ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: gcpleprod2
ingress.kubernetes.io/proxy-body-size: "0"
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.org/client-max-body-size: "0"
nginx.org/proxy-connect-timeout: "3600"
nginx.org/proxy-read-timeout: "3600"
nginx.org/websocket-services: fast-music-remover-service
name: fast-music-remover-service
namespace: default
spec:
rules:
- host: fms.steeped.space
http:
paths:
- backend:
service:
name: fast-music-remover-service
port:
number: 8080
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- fms.steeped.space
secretName: fast-music-remover-servicegcp-tls
And apply it
$ kubectl apply -f ./fastmusic.ingress.yaml
ingress.networking.k8s.io/fast-music-remover-service created
Once the cert is ready:
$ kubectl get cert fast-music-remover-servicegcp-tls
NAME READY SECRET AGE
fast-music-remover-servicegcp-tls True fast-music-remover-servicegcp-tls 74s
With the new URL, I’ll try again
This worked better. but i still get some clipping (as you can see here)
I can see this as useful, however, as there are times really old videos of mine are wrecked due to copyright strikes or old (now enforced) music issues.
I can recall a couple of video tapes and old DVD videos of my brothers I couldn’t put on YouTube because of background music.
Summary
Today we reviewed a couple fun and useful apps related to music. NextBeats is a fantastic little lo-fi background player one can use to just chill out or concentrate on homework or work. I demo’ed it to my eldest daughter the night I was writing that block and she just kept it playing the whole drive home. While I got a withering look when i asked if it was ‘fire’, she did give me a thumbs up, which is high praise from a teenager.
The background noise remover will be awesome if I record more tech presentation videos. The hallway-based quick presentations/tech talks are always the noisiest. Even if I’m recording someone else’s, that could be useful to trim out the distracting background chatter. I’ll leave this up for now and see if it get’s used.
You can try some of the apps as I’m hosting them locally: