Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Containerized branch based on 303-proxy_http_ffmpeg_streams #305

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
import cherrypy
import flask_babel
import psutil
from flask import (Flask, flash, make_response, redirect, render_template,
request, send_file, url_for)
import requests
from flask import (Flask, Response, flash, make_response, redirect,
render_template, request, send_file, url_for)
from flask_babel import Babel
from flask_paginate import Pagination, get_page_parameter
from selenium import webdriver
Expand Down Expand Up @@ -608,6 +609,27 @@ def expand_fs():
flash("You don't have permission to resize the filesystem", "is-danger")
return redirect(url_for("home"))

# Proxy the video stream from ffmpeg to /stream/<path>, so pikaraoke works over a single port
@app.route('/stream/<path>', methods=["GET", "POST"])
def redirect_to_ffmpeg_stream(path): #NOTE var :path will be unused as all path we need will be read from :request ie from flask import request
res = requests.request( # ref. https://stackoverflow.com/a/36601467/248616
method = request.method,
url = request.url.replace(request.host_url, f'{k.ffmpeg_url_base}/'),
headers = {k:v for k,v in request.headers if k.lower() != 'host'}, # exclude 'host' header
data = request.get_data(),
cookies = request.cookies,
allow_redirects = False,
)

#region exlcude some keys in :res response
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] #NOTE we here exclude all "hop-by-hop headers" defined by RFC 2616 section 13.5.1 ref. https://www.rfc-editor.org/rfc/rfc2616#section-13.5.1
headers = [
(k,v) for k,v in res.raw.headers.items()
if k.lower() not in excluded_headers
]
#endregion exclude some keys in :res response
response = Response(res.content, res.status_code, headers)
return response

# Handle sigterm, apparently cherrypy won't shut down without explicit handling
signal.signal(signal.SIGTERM, lambda signum, stack_frame: k.stop())
Expand All @@ -616,24 +638,7 @@ def get_default_youtube_dl_path(platform):
if platform == "windows":
return os.path.join(os.path.dirname(__file__), ".venv\Scripts\yt-dlp.exe")
return os.path.join(os.path.dirname(__file__), ".venv/bin/yt-dlp")
# if platform == "windows":
# choco_ytdl_path = r"C:\ProgramData\chocolatey\bin\yt-dlp.exe"
# scoop_ytdl_path = os.path.expanduser(r"~\scoop\shims\yt-dlp.exe")
# if os.path.isfile(choco_ytdl_path):
# return choco_ytdl_path
# if os.path.isfile(scoop_ytdl_path):
# return scoop_ytdl_path
# return r"C:\Program Files\yt-dlp\yt-dlp.exe"
# default_ytdl_unix_path = "/usr/local/bin/yt-dlp"
# if platform == "osx":
# if os.path.isfile(default_ytdl_unix_path):
# return default_ytdl_unix_path
# else:
# # just a guess based on the default python 3 install in OSX monterey
# return "/Library/Frameworks/Python.framework/Versions/3.10/bin/yt-dlp"
# else:
# return default_ytdl_unix_path



def get_default_dl_dir(platform):
if is_raspberry_pi:
Expand Down
20 changes: 20 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use Alpine as the base image
FROM alpine:latest

# Install required packages
RUN apk add --no-cache bash zsh git gcc python3-dev musl-dev linux-headers py3-pip ffmpeg htop screen figlet

# Clone the pikaraoke repository
RUN git clone -b PiKaraoke-Docker https://github.com/honestlai/pikaraoke.git /pikaraoke
honestlai marked this conversation as resolved.
Show resolved Hide resolved

# Run the setup script
RUN cd /pikaraoke && echo y | bash setup.sh

# Copy the entrypoint script into the container
COPY entrypoint.sh /entrypoint.sh

# Set permissions for the entrypoint script
RUN chmod +x /entrypoint.sh

# Set the entrypoint
ENTRYPOINT ["/entrypoint.sh"]
674 changes: 674 additions & 0 deletions docker/LICENSE

Large diffs are not rendered by default.

75 changes: 75 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

# Dockerized PiKaraoke

This repository contains a Dockerized version of PiKaraoke, a "KTV"-style karaoke song search and queueing system, originally designed to work on Raspberry Pi, OSX, Windows, and Linux. This container is built on alpine, making it easy to set up and run on any system with docker support.

## Features

- The Dockerized version retains all features of the original PiKaraoke.
- Easy to set up and run on any system with Docker support.
- Automatically exposes on port 5555.

## Prerequisites

- Docker and Docker Compose installed on your system.
- A reverse proxy like nginx is very helpful but not required.
- If using a reverse proxy http:// or https:// is required at the beginning of the URL variable
- The PASSWORD variable is optional.

## Installation and Launch

### Using Docker Compose Command Line

1. **Create a Docker Compose File**:
Create a `docker-compose.yml` file with the following content:
```yaml
version: '3'

services:
pikaraoke:
image: honestlai/pikaraoke-docker:latest
container_name: PiKaraoke
volumes:
- pikaraoke-songs:/pikaraoke-songs
environment:
URL: #https://karaoke.yourdomain.com
PASSWORD: #optionalpassword
restart: unless-stopped
ports:
- "5555:5555"

volumes:
pikaraoke-songs:
# Define your volume specifics here, if any.
```

2. **Running the Container**:
Use Docker Compose to pull the image and start the container:
```bash
docker-compose up -d
```

### Using Portainer

1. **Access Portainer**: Navigate to the 'Stacks' section.
2. **Add a New Stack**: Click on '+ Add stack'.
3. **Compose File**: Clone the repository or copy the `docker-compose.yml` content above.
4. **Environment Variables**: Add necessary variables like `URL` and `PASSWORD`.
5. **Deploy the Stack**: Click on 'Deploy the stack'.

### Building the Container Locally

1. **Clone this Dockerized repository**:
```bash
git clone https://github.com/vicwomg/pikaraoke.git
cd pikaraoke/docker
```

2. **Build and Run the Docker Container**:
```bash
docker-compose up --build
```

---
honestlai marked this conversation as resolved.
Show resolved Hide resolved

For more details on the project and additional features, please visit the [main repository page](https://github.com/vicwomg/pikaraoke).
18 changes: 18 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: '3'

services:
pikaraoke:
build: .
container_name: PiKaraoke
volumes:
- pikaraoke-songs:/pikaraoke-songs
environment:
URL: #https://karaoke.yourdomain.com
PASSWORD: #optionalpassword
restart: unless-stopped
ports:
- "5555:5555"

volumes:
pikaraoke-songs:
# Define your volume specifics here, if any.
22 changes: 22 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

# Correcting the URL format
URL=$(echo "$URL" | sed 's|/$||') # Remove trailing slash if exists
if ! echo "$URL" | grep -q "^https://"; then
URL="https://$URL" # Add https:// if not present
fi
honestlai marked this conversation as resolved.
Show resolved Hide resolved

# Exporting the corrected URL
export URL

# Run pikaraoke with environment variables
if [ -z "$PASSWORD" ]; then
figlet PiKaraoke
honestlai marked this conversation as resolved.
Show resolved Hide resolved
/pikaraoke/pikaraoke.sh -d /pikaraoke-songs/ --headless -u $URL
honestlai marked this conversation as resolved.
Show resolved Hide resolved
else
figlet PiKaraoke
/pikaraoke/pikaraoke.sh -d /pikaraoke-songs/ --headless -u $URL --admin-password $PASSWORD
fi

# Keep the container running
tail -f /dev/null
8 changes: 5 additions & 3 deletions karaoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def __init__(
# override with supplied constructor args if provided
self.port = port
self.ffmpeg_port = ffmpeg_port
self.ffmpeg_url_base = f"http://0.0.0.0:{self.ffmpeg_port}"
self.hide_url = hide_url
self.hide_raspiwifi_instructions = hide_raspiwifi_instructions
self.hide_splash_screen = hide_splash_screen
Expand Down Expand Up @@ -360,9 +361,10 @@ def get_youtube_id_from_url(self, url):
def play_file(self, file_path, semitones=0):
logging.info(f"Playing file: {file_path} transposed {semitones} semitones")
stream_uid = int(time.time())
stream_url = f"{self.url_parsed.scheme}://{self.url_parsed.hostname}:{self.ffmpeg_port}/{stream_uid}"
# pass a 0.0.0.0 IP to ffmpeg which will work for both hostnames and direct IP access
ffmpeg_url = f"http://0.0.0.0:{self.ffmpeg_port}/{stream_uid}"
# This is the stream URL that will be accessed by the splash screen client, Flask will
stream_url = f"{self.url}/stream/{stream_uid}"
# Used by ffmpeg, pass a 0.0.0.0 IP to ffmpeg which will work for both hostnames and direct IP access
ffmpeg_url = f"{self.ffmpeg_url_base}/{stream_uid}"

pitch = 2**(semitones/12) #The pitch value is (2^x/12), where x represents the number of semitones

Expand Down
Loading