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

Support Dockerized installation of pikaraoke #293

Open
honestlai opened this issue Dec 25, 2023 · 43 comments · May be fixed by #305
Open

Support Dockerized installation of pikaraoke #293

honestlai opened this issue Dec 25, 2023 · 43 comments · May be fixed by #305

Comments

@honestlai
Copy link

Love this project, wondering if it can be altered to be hosted.

I have a server that I run lots of docker stuff on. It crossed my mind that this would be great to dockerize if the splash screen could run outside of the host maybe over the net. I would of course protect it w/ something like SSO or an auth page via nginx.

I attempted to run the splash page externally on my systems browser with no luck. I'm guessing the audio stack in the scripting is pushing directly from the back end through the hosts sound system.

If this could be altered to have the audio+video render in the browser instead so it could run externally, that would be amazing!

-Matt

@honestlai
Copy link
Author

Hmm,

Now that I've read further into the documentation, I realized it sounds like --headless should accomplish what I'm trying to do, but when I que a song, my browser shows it's about to play, the title appears, but the video never start.

The logs show the song starting and then ending 10 seconds later... and then Song ending: none a minute or so after that. If I understand correctly, rendering should be done via ffmpeg and in the browser, but it's not streaming for some reason.

Anyone know why?

I've currently got an instance spun up in an ubuntu docker routed through nginx on my work server to my home Mac systems browser.

@vicwomg
Copy link
Owner

vicwomg commented Dec 26, 2023 via email

@honestlai
Copy link
Author

honestlai commented Dec 26, 2023 via email

@vicwomg
Copy link
Owner

vicwomg commented Dec 26, 2023

Yes, there are CLI args for this:

  -p PORT, --port PORT  Desired http port (default: 5555)
  -f FFMPEG_PORT, --ffmpeg-port FFMPEG_PORT
                        Desired ffmpeg port. This is where video stream URLs will be pointed (default: 5556)

Run pikaraoke.sh --help for the full list of options

@honestlai
Copy link
Author

Thanks, ya, I saw that just before I went to bed last night. I think what I might try to do is build a dockerized container for this that uses nginx to wrap the services into a single output on 80 so it can be pushed through a reverse proxy like the other services I run on my home server.

From what I've been reading, this should work. I haven't built a custom container in awhile, should be fun.

@honestlai
Copy link
Author

Hmm...

After analyzing how the videos are streamed in Chrome, I can see the player is inside a frame, playing on port 5556 and the url is based on the url either set in the -u flag or based on the hostname of the host. I'm gonna see if I can separate this and maybe place the base root of the streaming at /video or /stream? That way I think I can have nginx proxy the streaming requests based on that.

@vicwomg
Copy link
Owner

vicwomg commented Dec 26, 2023

I couldn't figure out how to have them live on the same port. ffmpeg complains if you set the port to the same one as the python http server

@honestlai
Copy link
Author

honestlai commented Dec 26, 2023

OMG! I figured it out! it's up and running through nginx and cloudflare!

I edited karaoke.py with the following
... I added /video-stream/ to the stream_url and ffmpeg_url. Also had to remove the port for the stream 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}/video-stream/{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}/video-stream/{stream_uid}"

and then the below is my nginx config. My outter nginx reverse proxy that faces the internet accesses the karaoke servers nginx service at port 80 which has both ffmpeg and the gui wraped in together with the below config.

# For the web interface
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:5555;  # Web interface
        # ... other proxy settings ...
    }

    location /video-stream/ {
        proxy_pass http://localhost:5556;  # FFmpeg server
        # ... other proxy settings ...
    }
}

@honestlai
Copy link
Author

honestlai commented Dec 26, 2023

I couldn't figure out how to have them live on the same port. ffmpeg complains if you set the port to the same one as the python http server

Ya, according to GPT, it's standard to have video streaming running over a separate port like this and to use either a reverse proxy or websocket to combine everything into an interface running on a single port. I'm pretty lazy and usually do this stuff through a simplified web interface that controls my nginx setups, so this was a first for me standing up an nginx server and manipulating it through the config files directly.

If I have time this week, I'll start working on a container repository where my tinkering with this can live, and get a build uploaded to docker hub.

Also, fyi, my test environment I'm running this is is alpine... it runs great!

@honestlai
Copy link
Author

honestlai commented Dec 26, 2023

Also, just edited the confirm button on the splash page so it automatically pushes the browser to go full screen. Dunno if it would mess up the local instance or not on the pi... don't think it should

<script>
  // ... existing JavaScript ...

  function handleConfirmation() {
    $("#permissions-modal").removeClass("is-active");
    confirmationDismissed = true;
    goFullScreen();
  }

  function goFullScreen() {
    var elem = document.documentElement; // Get the document's root element
    if (elem.requestFullscreen) {
      elem.requestFullscreen();
    } else if (elem.mozRequestFullScreen) { /* Firefox */
      elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
      elem.webkitRequestFullscreen();
    } else if (elem.msRequestFullscreen) { /* IE/Edge */
      elem.msRequestFullscreen();
    }
  }

  // ... rest of the JavaScript ...
</script>

@honestlai
Copy link
Author

honestlai commented Dec 27, 2023

Now that I'm able to host this on a distant server over the internet either on my Pi or docker server, it's looking like I can run the player on any browser distantly.

The one thing I've found now is it seems like I can only run the player on Mac, Windows, and the Pi desktop environment. When I tried to bring the splash page up on my phone or iPad, the videos don't play. Guessing it would be the same on my Fire tablet (haven't checked yet).

Any idea why it doesn't want to play on mobile?

@vicwomg
Copy link
Owner

vicwomg commented Dec 27, 2023

My first guess would be safari is blocking it in some way. Safari's browser permissions are likely more restrictive than chrome

@honestlai
Copy link
Author

honestlai commented Dec 27, 2023

Ok... just checked on an old Fire tablet I forgot I had. It worked. So it looks like it's an iOS thing. The splash page just doesn't play videos on my iPhone and iPad. I've tried Safari, Chrome, and Firefox.

@RecursiveFunctions
Copy link

From Phind:

on iOS, how do i make the browser automatically play videos and audio, using python? or HTML5?

To make a browser automatically play videos and audio on iOS devices, you would typically use HTML5's <video> or <audio> tags with the autoplay attribute. However, due to the limitations of mobile devices and user experience considerations, autoplay might not always work as expected. Here are some steps to ensure your media files play automatically on iOS devices:

  1. Use the autoplay, loop, muted, and playsinline attributes: These attributes help control the autoplay behavior of the video or audio file. The autoplay attribute allows the media to start playing automatically, loop makes the media restart once it finishes, muted ensures the media doesn't play with sound, and playsinline allows the video to play inline in the webpage, rather than fullscreen.
<video autoplay loop muted playsinline>
 <source src="your_video_file.mp4" type="video/mp4">
</video>

Source 0

  1. Disable "Low Power Mode" on your iPhone: iOS devices have a "Low Power Mode" which restricts certain features, including autoplay. You cannot control this setting programmatically, but you can instruct users to disable it for a better experience.

  2. Check Autoplay Policy: Use the Navigator.getAutoplayPolicy() method to check if autoplay is allowed, disallowed, or only supported for inaudible content. Depending on the result, you may need to adjust your media settings accordingly.

if (navigator.getAutoplayPolicy("mediaelement") === "allowed") {
 // The video element will autoplay with audio.
} else if (navigator.getAutoplayPolicy("mediaelement") === "allowed-muted") {
 // Mute audio on video
 video.muted = true;
} else if (navigator.getAutoplayPolicy("mediaelement") === "disallowed") {
 // Set a default placeholder image.
 video.poster = "http://example.com/poster_image_url";
}

Source 4

  1. Handle Autoplay Failures: If autoplay fails, you might want to offer a way for the user to manually start the media. You can use the play() method which returns a Promise, allowing you to handle success or failure of the operation.
let startPlayPromise = videoElem.play();

if (startPlayPromise !== undefined) {
 startPlayPromise
   .then(() => {
     // Start whatever you need to do only after playback
     // has begun.
   })
   .catch((error) => {
     if (error.name === "NotAllowedError") {
       showPlayButton(videoElem);
     } else {
       // Handle a load or playback error
     }
   });
}

Source 4

Try disabling low power mode on your iOS device and see if that lets it autoplay

@honestlai
Copy link
Author

ahh... nice resource. Will have to dig in when I have time.

I'm very new to posting on github, and using code from another repository. I'm going to build my own deployable container that will pull from this repository with my own changes/contributions. I was just wondering if there is a proper procedure or guideline I should be following for doing this.

@RecursiveFunctions
Copy link

Code should preferably be cross-platform. I tried to implement something that got sidelined because it was only relevant to Raspberry Pi OS and wouldn't work for windows or MacOS

@honestlai
Copy link
Author

Python is pretty platform agnostic… as long as dependencies are met, not sure why this wouldn’t work on other platforms… that’s part of what I’m trying to accomplish with doing a containerized version of this

@RecursiveFunctions
Copy link

Python is pretty platform agnostic… as long as dependencies are met, not sure why this wouldn’t work on other platforms… that’s part of what I’m trying to accomplish with doing a containerized version of this

You should be fine, I only mention the cross plat-form thing since some parts of this repo have bash scripts and i did mine in bash instead of python

@vicwomg
Copy link
Owner

vicwomg commented Dec 27, 2023 via email

@honestlai
Copy link
Author

honestlai commented Dec 27, 2023

... you’ll eventually fall out of sync and have conflicting code. Third, the main project doesn’t get to benefit from your changes. And things get fractured. Ideally you’d contribute your changes back by opening a pull request to the master project. I’d appreciate it and can help

Ahh yes, I definitely wouldn't want to go out of sync with updates and additions to the project. I've never contributed to a repository before, but would love to help where I can, just don't know where to start and how not to step on digital toes.

As for the docker side of things, I'm going to build out a separate project (that pulls from this repository for each build), and set it up like how I've seen others... ideally like Binhex or Linuxserver.

@honestlai
Copy link
Author

I stayed up way later than I should have working on this, but the docker repos are up.
https://github.com/honestlai/pikaraoke-docker
https://hub.docker.com/repository/docker/honestlai/pikaraoke-docker/general

I gotta fix the instructions a little and flesh it out a little more (was a bit blurry eyed by the time I went to bed), but it's tested and working. I spun up a test instance here on one of my throw-away VPS's.

I made some css changes to the splash.html file. How would I go about contributing those changes to this repo?

@vicwomg
Copy link
Owner

vicwomg commented Dec 27, 2023

@honestlai guide here on how to open a pull request:

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request

The gist is:

  • create a fork of this project
  • make your edits
  • submit a "pull request" with a description of the changes
  • maintainers (me) will review and may ask for changes to make it suitable for merge
  • maintainer approves and merges the pull request. Your code is now in master!

@vicwomg
Copy link
Owner

vicwomg commented Dec 27, 2023

I'm curious though, why docker hosting required changes to /splash. Be sure to clearly explain those changes and why they are necessary

@vicwomg
Copy link
Owner

vicwomg commented Dec 27, 2023

Finally, while you're at it, I'd love some documentation in the README.md about how to dockerize. So you could include that in your PR. It can even simply link to your github docker project

@honestlai
Copy link
Author

why docker hosting required changes to /splash. Be sure to clearly explain those changes and why they are necessary

Oh... it wasn't totally needed (mostly visual polish). I found occasionally the background animations or titles in some of the karaoke videos would interfere with the titles and QR code visibility.

The only required change I had to make to your code was in karaoke.py, moving the video stream path from the root to /video-stream/ so the included nginx reverse proxy could stream the port data on the same port as the gui.

I'd love some documentation in the README.md about how to dockerize. So you could include that in your PR. It can even simply link to your github docker project

Not sure I'm following... like instructions for you to place in your repo? Or more clear instructions on my dockerized repo of what I did?

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

@honestlai I see, thats great. So those changes are not directly related to this branch. That being the case, please open a new ticket describing the issues and mention that in your PR. Usually PRs are linked to a issue ticket

I mean as part of your PR, you can edit the README.md of this project and add a section in the Troubleshooting/FAQ about setting up docker containers. It can link to your github project so future users who come here can find it.

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

The only required change I had to make to your code was in karaoke.py, moving the video stream path from the root to /video-stream/ so the included nginx reverse proxy could stream the port data on the same port as the gui.

You should make a PR for this, and ensure that it doesn't break the default functionality of users who are not running in docker. If it does, you need to make these changes a command line option that can be enabled/disabled

@honestlai
Copy link
Author

You should make a PR for this, and ensure that it doesn't break the default functionality of users who are not running in docker. If it does, you need to make these changes a command line option that can be enabled/disabled

I'll play with it on my raspberry pi where I was doing most of the initial edits and see if the local instance still works. I have a feeling it won't without some additional tweaking.

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

Looking more closely at your docker project, I don't see why this all can't live under a /docker subdirectory of this project with some path modification. Would be nice if folks didn't have to jump around to different projects.

I can also see the lines where you're patching karaoke.py with sed . Yeah, let's find a way to make both work without monkey patching. It would be much cleaner.

@honestlai
Copy link
Author

honestlai commented Dec 28, 2023

Looking more closely at your docker project, I don't see why this all can't live under a /docker subdirectory of this project with some path modification. Would be nice if folks didn't have to jump around to different projects.

Sure! I have no problem with that... I've never done a PR, so didn't know where to start with that (I've been browsing through the KB you sent), would be happy to offer my contribution to this.

I can also see the lines where you're patching karaoke.py with sed . Yeah, let's find a way to make both work without monkey patching. It would be much cleaner.

Ya, I'm looking at including an if statement to check if self.url_parsed.scheme is equal to the hostname or ip... and if it isn't, the :{self.ffmpeg_port} would come off the url line... without this, the self-hosted player does not work properly w/ my modifications.

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

Wow, around the same time we're discussing this, this PR came in:

#301

Does this solve the problem? Basically means you can override the default ffmpeg url with --fmpeg-url <your_url>

@honestlai
Copy link
Author

Wow, around the same time we're discussing this, this PR came in:

#301

Does this solve the problem? Basically means you can override the default ffmpeg url with --fmpeg-url <your_url>

it kind of sort of fixes the issue, but it's not as streamlined as pushing the 2 streams of data through a single port using something like nginx. It's funny tho, nathanpalmer is trying to get around the same exact thing I was.

@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

All this got me thinking, instead wrapping all this proxying externally, why not just do it inside pikaraoke? It has its own http server: Flask.

Turned out to be pretty simple to do. Check this branch out:

303-proxy_http_ffmpeg_streams
#304

Seems to run just fine on one port. LMK if that solves these problems

@honestlai
Copy link
Author

Nice… That’s perfect! I was wondering if that were possible. I’ve never taken the time to learn flask, will have to play with it eventually.

So does this mean both the gui and video streams output over 5555? This definitely makes some of what was working on easier.

@honestlai
Copy link
Author

Since I've been able to successfully get this built and deployed on a few different servers, I think I can call this issue resolved. I'm gonna read up on doing a PR now and submit what I've built so far.

@honestlai honestlai changed the title Non-local hosting Non-local hosting *Solved* Dec 28, 2023
@honestlai honestlai reopened this Dec 28, 2023
@vicwomg vicwomg reopened this Dec 28, 2023
@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

I wouldn't call this closed until changes are merged to master

@vicwomg vicwomg changed the title Non-local hosting *Solved* Support Dockerized installation of pikaraoke Dec 28, 2023
@vicwomg
Copy link
Owner

vicwomg commented Dec 28, 2023

changing the focus of this ticket to Docker

@honestlai
Copy link
Author

Sounds good. I'm about to push an update to the PR. I think I adjusted for the notes you gave and also took most of the day intermittently to implement a full screen button next to the nav button. Added a transparency as well so it's easier to see on background like in the pic below.

image

@Jamalarm
Copy link

@vicwomg I would be interested in helping out with getting the dockerized build over the line and into main. It seems like the open PR has a bunch of unrelated UI changes in it which prevented it from being merged. Would you accept a PR focused only on getting the docker build working?

Ideally we could then start publishing an official image to docker hub, and then the setup on a new server would really just be as easy as docker run pikaraoke:latest

@vicwomg
Copy link
Owner

vicwomg commented Sep 23, 2024 via email

@vicwomg
Copy link
Owner

vicwomg commented Sep 23, 2024 via email

@astrobyte
Copy link

Looking forward to this. I'm excited to see how this project is coming along

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants