From 04e82533c795b10c40f533d09071e4be8c543889 Mon Sep 17 00:00:00 2001 From: VergilGao <8655163+VergilGao@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:21:15 +0800 Subject: [PATCH 1/3] Add a supports_reuse_port method to check if the operating system supports reuse port. --- app/main.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/main.py b/app/main.py index 48826df..4bad876 100644 --- a/app/main.py +++ b/app/main.py @@ -4,6 +4,7 @@ import os import sys from aiohttp import web +import socket import socketio import logging import json @@ -247,8 +248,16 @@ async def on_prepare(request, response): app.on_response_prepare.append(on_prepare) +def supports_reuse_port(): + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.close() + return True + except (AttributeError, OSError): + return False if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) log.info(f"Listening on {config.HOST}:{config.PORT}") - web.run_app(app, host=config.HOST, port=int(config.PORT), reuse_port=True) + web.run_app(app, host=config.HOST, port=int(config.PORT), reuse_port=supports_reuse_port()) From 84ed2c5f00b2af4026994f13029ad14e27979042 Mon Sep 17 00:00:00 2001 From: VergilGao <8655163+VergilGao@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:54:36 +0800 Subject: [PATCH 2/3] Add the ability to be configured as an HTTPS service --- README.md | 25 +++++++++++++++++++++++++ app/main.py | 12 +++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54e4451..4a3b420 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ docker run -d -p 8081:8081 -v /path/to/downloads:/downloads ghcr.io/alexta69/met ## Run using docker-compose +serve a http host: + ```yaml services: metube: @@ -29,6 +31,26 @@ services: - /path/to/downloads:/downloads ``` +serve a https host: + +```yaml +services: + metube: + image: ghcr.io/alexta69/metube + container_name: metube + restart: unless-stopped + ports: + - "8081:8081" + volumes: + - /path/to/downloads:/downloads + - /path/to/ssl/crt:/ssl/crt.pem + - /path/to/ssl/key:/ssl/key.pem + environment: + - HTTPS=true + - CERTFILE=/ssl/crt.pem + - KEYFILE=/ssl/key.pem +``` + ## Configuration via environment variables Certain values can be set via environment variables, using the `-e` parameter on the docker command line, or the `environment:` section in docker-compose. @@ -49,6 +71,9 @@ Certain values can be set via environment variables, using the `-e` parameter on * __DELETE_FILE_ON_TRASHCAN__: if `true`, downloaded files are deleted on the server, when they are trashed from the "Completed" section of the UI. Defaults to `false`. * __URL_PREFIX__: base path for the web server (for use when hosting behind a reverse proxy). Defaults to `/`. * __PUBLIC_HOST_URL__: base URL for the download links shown in the UI for completed files. By default MeTube serves them under its own URL. If your download directory is accessible on another URL and you want the download links to be based there, use this variable to set it. +* __HTTPS__: use `https` instead of `http`(__CERTFILE__ and __KEYFILE__ required). Defaults to `false`. +* __CERTFILE__: HTTPS certificate file path. Defaults to ` `. +* __KEYFILE__: HTTPS key file path. Defaults to ` `. * __PUBLIC_HOST_AUDIO_URL__: same as PUBLIC_HOST_URL but for audio downloads. * __OUTPUT_TEMPLATE__: the template for the filenames of the downloaded videos, formatted according to [this spec](https://github.com/yt-dlp/yt-dlp/blob/master/README.md#output-template). Defaults to `%(title)s.%(ext)s`. * __OUTPUT_TEMPLATE_CHAPTER__: the template for the filenames of the downloaded videos, when split into chapters via postprocessors. Defaults to `%(title)s - %(section_number)s %(section_title)s.%(ext)s`. diff --git a/app/main.py b/app/main.py index 4bad876..351fdad 100644 --- a/app/main.py +++ b/app/main.py @@ -4,6 +4,7 @@ import os import sys from aiohttp import web +import ssl import socket import socketio import logging @@ -36,6 +37,9 @@ class Config: 'YTDL_OPTIONS_FILE': '', 'HOST': '0.0.0.0', 'PORT': '8081', + 'HTTPS': 'false', + 'CERTFILE': '', + 'KEYFILE': '', 'BASE_DIR': '', 'DEFAULT_THEME': 'auto' } @@ -260,4 +264,10 @@ def supports_reuse_port(): if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) log.info(f"Listening on {config.HOST}:{config.PORT}") - web.run_app(app, host=config.HOST, port=int(config.PORT), reuse_port=supports_reuse_port()) + + if config.HTTPS: + ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_context.load_cert_chain(certfile=config.CERTFILE, keyfile=config.KEYFILE) + web.run_app(app, host=config.HOST, port=int(config.PORT), reuse_port=supports_reuse_port(), ssl_context=ssl_context) + else: + web.run_app(app, host=config.HOST, port=int(config.PORT), reuse_port=supports_reuse_port()) From 07b0b9caed9ceda863f1c93cedc2b0789a8f031e Mon Sep 17 00:00:00 2001 From: Alex Shnitman Date: Wed, 11 Sep 2024 19:40:45 +0300 Subject: [PATCH 3/3] documentation fixes and HTTPS boolean fix --- README.md | 52 +++++++++++++++++++++++++--------------------------- app/main.py | 2 +- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 4a3b420..4d40542 100644 --- a/README.md +++ b/README.md @@ -17,22 +17,6 @@ docker run -d -p 8081:8081 -v /path/to/downloads:/downloads ghcr.io/alexta69/met ## Run using docker-compose -serve a http host: - -```yaml -services: - metube: - image: ghcr.io/alexta69/metube - container_name: metube - restart: unless-stopped - ports: - - "8081:8081" - volumes: - - /path/to/downloads:/downloads -``` - -serve a https host: - ```yaml services: metube: @@ -43,12 +27,6 @@ services: - "8081:8081" volumes: - /path/to/downloads:/downloads - - /path/to/ssl/crt:/ssl/crt.pem - - /path/to/ssl/key:/ssl/key.pem - environment: - - HTTPS=true - - CERTFILE=/ssl/crt.pem - - KEYFILE=/ssl/key.pem ``` ## Configuration via environment variables @@ -72,8 +50,8 @@ Certain values can be set via environment variables, using the `-e` parameter on * __URL_PREFIX__: base path for the web server (for use when hosting behind a reverse proxy). Defaults to `/`. * __PUBLIC_HOST_URL__: base URL for the download links shown in the UI for completed files. By default MeTube serves them under its own URL. If your download directory is accessible on another URL and you want the download links to be based there, use this variable to set it. * __HTTPS__: use `https` instead of `http`(__CERTFILE__ and __KEYFILE__ required). Defaults to `false`. -* __CERTFILE__: HTTPS certificate file path. Defaults to ` `. -* __KEYFILE__: HTTPS key file path. Defaults to ` `. +* __CERTFILE__: HTTPS certificate file path. +* __KEYFILE__: HTTPS key file path. * __PUBLIC_HOST_AUDIO_URL__: same as PUBLIC_HOST_URL but for audio downloads. * __OUTPUT_TEMPLATE__: the template for the filenames of the downloaded videos, formatted according to [this spec](https://github.com/yt-dlp/yt-dlp/blob/master/README.md#output-template). Defaults to `%(title)s.%(ext)s`. * __OUTPUT_TEMPLATE_CHAPTER__: the template for the filenames of the downloaded videos, when split into chapters via postprocessors. Defaults to `%(title)s - %(section_number)s %(section_title)s.%(ext)s`. @@ -139,7 +117,7 @@ iOS has strict requirements for video files, requiring h264 or h265 video codec ## Bookmarklet -[kushfest](https://github.com/kushfest) has created a Chrome bookmarklet for sending the currently open webpage to MeTube. Please note that if you're on an HTTPS page, your MeTube instance must be behind an HTTPS reverse proxy (see below) for the bookmarklet to work. +[kushfest](https://github.com/kushfest) has created a Chrome bookmarklet for sending the currently open webpage to MeTube. Please note that if you're on an HTTPS page, your MeTube instance must be configured with `HTTPS` as `true` in the environment, or be behind an HTTPS reverse proxy (see below) for the bookmarklet to work. GitHub doesn't allow embedding JavaScript as a link, so the bookmarklet has to be created manually by copying the following code to a new bookmark you create on your bookmarks bar. Change the hostname in the URL below to point to your MeTube instance. @@ -167,9 +145,29 @@ Firefox: javascript:(function(){function notify(msg) {var sc = document.scrollingElement.scrollTop; var text = document.createElement('span');text.innerHTML=msg;var ts = text.style;ts.all = 'revert';ts.color = '#000';ts.fontFamily = 'Verdana, sans-serif';ts.fontSize = '15px';ts.backgroundColor = 'white';ts.padding = '15px';ts.border = '1px solid gainsboro';ts.boxShadow = '3px 3px 10px';ts.zIndex = '100';document.body.appendChild(text);ts.position = 'absolute'; ts.top = 50 + sc + 'px'; ts.left = (window.innerWidth / 2)-(text.offsetWidth / 2) + 'px'; setTimeout(function () { text.style.visibility = "hidden"; }, 1500);}xhr=new XMLHttpRequest();xhr.open("POST","https://metube.domain.com/add");xhr.send(JSON.stringify({"url":document.location.href,"quality":"best"}));xhr.onload=function() { if(xhr.status==200){notify("Sent to metube!")}else {notify("Send to metube failed. Check the javascript console for clues.")}}})(); ``` -## Running behind a reverse proxy +## HTTPS support, and running behind a reverse proxy + +It's possible to configure MeTube to listen in HTTPS mode. `docker-compose` example: + +```yaml +services: + metube: + image: ghcr.io/alexta69/metube + container_name: metube + restart: unless-stopped + ports: + - "8081:8081" + volumes: + - /path/to/downloads:/downloads + - /path/to/ssl/crt:/ssl/crt.pem + - /path/to/ssl/key:/ssl/key.pem + environment: + - HTTPS=true + - CERTFILE=/ssl/crt.pem + - KEYFILE=/ssl/key.pem +``` -It's advisable to run MeTube behind a reverse proxy, if authentication and/or HTTPS support are required. +It's also possible to run MeTube behind a reverse proxy, in order to support authentication. HTTPS support can also be added in this way. When running behind a reverse proxy which remaps the URL (i.e. serves MeTube under a subdirectory and not under root), don't forget to set the URL_PREFIX environment variable to the correct value. diff --git a/app/main.py b/app/main.py index 351fdad..9e10242 100644 --- a/app/main.py +++ b/app/main.py @@ -44,7 +44,7 @@ class Config: 'DEFAULT_THEME': 'auto' } - _BOOLEAN = ('DOWNLOAD_DIRS_INDEXABLE', 'CUSTOM_DIRS', 'CREATE_CUSTOM_DIRS', 'DELETE_FILE_ON_TRASHCAN', 'DEFAULT_OPTION_PLAYLIST_STRICT_MODE') + _BOOLEAN = ('DOWNLOAD_DIRS_INDEXABLE', 'CUSTOM_DIRS', 'CREATE_CUSTOM_DIRS', 'DELETE_FILE_ON_TRASHCAN', 'DEFAULT_OPTION_PLAYLIST_STRICT_MODE', 'HTTPS') def __init__(self): for k, v in self._DEFAULTS.items():