initial commit
This commit is contained in:
403
core/0001.patch
Normal file
403
core/0001.patch
Normal file
@@ -0,0 +1,403 @@
|
||||
diff --git a/settings.py b/settings.py
|
||||
index 1482db0..065954e 100644
|
||||
--- a/settings.py
|
||||
+++ b/settings.py
|
||||
@@ -452,6 +452,6 @@ def settings_page():
|
||||
|
||||
globals().update(current_settings_dict)
|
||||
save_settings(current_settings_dict)
|
||||
- return flask.redirect(util.URL_ORIGIN + '/settings', 303)
|
||||
+ return flask.redirect(util.URL_ORIGIN)
|
||||
else:
|
||||
flask.abort(400)
|
||||
diff --git a/youtube/__init__.py b/youtube/__init__.py
|
||||
index 3c85d47..05fa3a5 100644
|
||||
--- a/youtube/__init__.py
|
||||
+++ b/youtube/__init__.py
|
||||
@@ -13,9 +13,6 @@ yt_app.url_map.strict_slashes = False
|
||||
# yt_app.jinja_env.lstrip_blocks = True
|
||||
|
||||
|
||||
-yt_app.add_url_rule('/settings', 'settings_page', settings.settings_page, methods=['POST', 'GET'])
|
||||
-
|
||||
-
|
||||
@yt_app.route('/')
|
||||
def homepage():
|
||||
return flask.render_template('home.html', title="Youtube local")
|
||||
diff --git a/youtube/static/channel.css b/youtube/static/channel.css
|
||||
index ada086d..3d2d36a 100644
|
||||
--- a/youtube/static/channel.css
|
||||
+++ b/youtube/static/channel.css
|
||||
@@ -270,11 +270,9 @@ hr {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/static/local_playlist.css b/youtube/static/local_playlist.css
|
||||
index 33771f4..1689b31 100644
|
||||
--- a/youtube/static/local_playlist.css
|
||||
+++ b/youtube/static/local_playlist.css
|
||||
@@ -246,11 +246,9 @@ hr {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/static/playlist.css b/youtube/static/playlist.css
|
||||
index 8438ceb..a614056 100644
|
||||
--- a/youtube/static/playlist.css
|
||||
+++ b/youtube/static/playlist.css
|
||||
@@ -256,11 +256,9 @@ hr {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/static/search.css b/youtube/static/search.css
|
||||
index ff1fbda..b9b7952 100644
|
||||
--- a/youtube/static/search.css
|
||||
+++ b/youtube/static/search.css
|
||||
@@ -274,11 +274,9 @@ hr {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/static/subscription.css b/youtube/static/subscription.css
|
||||
index 2004bd6..9a963ba 100644
|
||||
--- a/youtube/static/subscription.css
|
||||
+++ b/youtube/static/subscription.css
|
||||
@@ -250,11 +250,9 @@ hr {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/static/watch.css b/youtube/static/watch.css
|
||||
index 8d23017..dd83da3 100644
|
||||
--- a/youtube/static/watch.css
|
||||
+++ b/youtube/static/watch.css
|
||||
@@ -385,11 +385,9 @@ label[for=options-toggle-cbox] {
|
||||
|
||||
.item-box {
|
||||
display: grid;
|
||||
- grid-template-columns: 1.9fr 0.1fr;
|
||||
+ grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
- grid-gap: 1px;
|
||||
- grid-template-areas:
|
||||
- "item-video item-checkbox";
|
||||
+ grid-template-areas: "item-video";
|
||||
}
|
||||
|
||||
.item-video {
|
||||
diff --git a/youtube/templates/base.html b/youtube/templates/base.html
|
||||
index 7b32d76..5f60b40 100644
|
||||
--- a/youtube/templates/base.html
|
||||
+++ b/youtube/templates/base.html
|
||||
@@ -117,22 +117,6 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
- {% if header_playlist_names is defined %}
|
||||
- <form class="playlist" id="playlist-edit" action="/youtube.com/edit_playlist" method="post" target="_self">
|
||||
- <input class="play-box" name="playlist_name" id="playlist-name-selection" list="playlist-options" type="search" placeholder="I added your playlist...">
|
||||
- <datalist class="play-hidden" id="playlist-options">
|
||||
- {% for playlist_name in header_playlist_names %}
|
||||
- <option value="{{ playlist_name }}">{{ playlist_name }}</option>
|
||||
- {% endfor %}
|
||||
- </datalist>
|
||||
- <button class="play-add" type="submit" id="playlist-add-button" name="action" value="add">+List</button>
|
||||
- <div class="play-clean">
|
||||
- <button type="reset" id="item-selection-reset">Clear selection</button>
|
||||
- </div>
|
||||
- </form>
|
||||
- <script src="/youtube.com/static/js/playlistadd.js"></script>
|
||||
- {% endif %}
|
||||
-
|
||||
</header>
|
||||
<main class="main">
|
||||
|
||||
diff --git a/youtube/templates/channel.html b/youtube/templates/channel.html
|
||||
index 294f1df..a4361c3 100644
|
||||
--- a/youtube/templates/channel.html
|
||||
+++ b/youtube/templates/channel.html
|
||||
@@ -21,14 +21,6 @@
|
||||
<div class="summary">
|
||||
<p>{{ short_description }}</p>
|
||||
</div>
|
||||
- <div class="subscribe">
|
||||
- <form method="POST" action="/youtube.com/subscriptions" class="subscribe-unsubscribe">
|
||||
- <input class="btn-subscribe" type="submit" value="{{ 'Unsubscribe' if subscribed else 'Subscribe' }}">
|
||||
- <input type="hidden" name="channel_id" value="{{ channel_id }}">
|
||||
- <input type="hidden" name="channel_name" value="{{ channel_name }}">
|
||||
- <input type="hidden" name="action" value="{{ 'unsubscribe' if subscribed else 'subscribe' }}">
|
||||
- </form>
|
||||
- </div>
|
||||
</div>
|
||||
<hr/>
|
||||
|
||||
diff --git a/youtube/templates/common_elements.html b/youtube/templates/common_elements.html
|
||||
index 94554d4..7ba904a 100644
|
||||
--- a/youtube/templates/common_elements.html
|
||||
+++ b/youtube/templates/common_elements.html
|
||||
@@ -59,9 +59,6 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
- {% if info['type'] == 'video' %}
|
||||
- <input class="item-checkbox" type="checkbox" name="video_info_list" value="{{ info['video_info'] }}" form="playlist-edit">
|
||||
- {% endif %}
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endmacro %}
|
||||
diff --git a/youtube/templates/home.html b/youtube/templates/home.html
|
||||
index ef1f029..b537cca 100644
|
||||
--- a/youtube/templates/home.html
|
||||
+++ b/youtube/templates/home.html
|
||||
@@ -4,10 +4,4 @@
|
||||
<link href="/youtube.com/static/home.css" rel="stylesheet"/>
|
||||
{% endblock style %}
|
||||
{% block main %}
|
||||
- <ul>
|
||||
- <li><a href="/youtube.com/playlists">Local playlists</a></li>
|
||||
- <li><a href="/youtube.com/subscriptions">Subscriptions</a></li>
|
||||
- <li><a href="/youtube.com/subscription_manager">Subscription Manager</a></li>
|
||||
- <li><a href="/youtube.com/settings">Settings</a></li>
|
||||
- </ul>
|
||||
{% endblock main %}
|
||||
diff --git a/youtube/templates/settings.html b/youtube/templates/settings.html
|
||||
index 7a7ce9e..4749d4c 100644
|
||||
--- a/youtube/templates/settings.html
|
||||
+++ b/youtube/templates/settings.html
|
||||
@@ -5,43 +5,5 @@
|
||||
{% endblock style %}
|
||||
|
||||
{% block main %}
|
||||
- <form method="POST" class="settings-form">
|
||||
- {% for categ in categories %}
|
||||
- <h2>{{ categ|capitalize }}</h2>
|
||||
- <ul class="settings-list">
|
||||
- {% for setting_name, setting_info, value in settings_by_category[categ] %}
|
||||
- {% if not setting_info.get('hidden', false) %}
|
||||
- <li class="setting-item">
|
||||
- {% if 'label' is in(setting_info) %}
|
||||
- <label for="{{ 'setting_' + setting_name }}">{{ setting_info['label'] }}</label>
|
||||
- {% else %}
|
||||
- <label for="{{ 'setting_' + setting_name }}">{{ setting_name.replace('_', ' ')|capitalize }}</label>
|
||||
- {% endif %}
|
||||
|
||||
- {% if setting_info['type'].__name__ == 'bool' %}
|
||||
- <input type="checkbox" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" {{ 'checked' if value else '' }}>
|
||||
- {% elif setting_info['type'].__name__ == 'int' %}
|
||||
- {% if 'options' is in(setting_info) %}
|
||||
- <select id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}">
|
||||
- {% for option in setting_info['options'] %}
|
||||
- <option value="{{ option[0] }}" {{ 'selected' if option[0] == value else '' }}>{{ option[1] }}</option>
|
||||
- {% endfor %}
|
||||
- </select>
|
||||
- {% else %}
|
||||
- <input type="number" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}" step="1">
|
||||
- {% endif %}
|
||||
- {% elif setting_info['type'].__name__ == 'float' %}
|
||||
-
|
||||
- {% elif setting_info['type'].__name__ == 'str' %}
|
||||
- <input type="text" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}">
|
||||
- {% else %}
|
||||
- <span>Error: Unknown setting type: setting_info['type'].__name__</span>
|
||||
- {% endif %}
|
||||
- </li>
|
||||
- {% endif %}
|
||||
- {% endfor %}
|
||||
- </ul>
|
||||
- {% endfor %}
|
||||
- <input type="submit" value="Save settings">
|
||||
- </form>
|
||||
{% endblock main %}
|
||||
diff --git a/youtube/templates/subscription_manager.html b/youtube/templates/subscription_manager.html
|
||||
index 92cd024..c8eb603 100644
|
||||
--- a/youtube/templates/subscription_manager.html
|
||||
+++ b/youtube/templates/subscription_manager.html
|
||||
@@ -16,52 +16,5 @@
|
||||
{% endmacro %}
|
||||
|
||||
{% block main %}
|
||||
- <div class="import-export">
|
||||
- <form class="subscriptions-import-form" enctype="multipart/form-data" action="/youtube.com/import_subscriptions" method="POST">
|
||||
- <h2>Import subscriptions</h2>
|
||||
- <input type="file" id="subscriptions-import" accept="application/json, application/xml, text/x-opml" name="subscriptions_file">
|
||||
- <input type="submit" value="Import" class="import-submit-button">
|
||||
- </form>
|
||||
-
|
||||
- <!--<ul class="subscriptions-export-links">
|
||||
- <li><a href="/youtube.com/subscriptions.opml">Export subscriptions (OPML)</a></li>
|
||||
- <li><a href="/youtube.com/subscriptions.xml">Export subscriptions (RSS)</a></li>
|
||||
- </ul>-->
|
||||
- </div>
|
||||
-
|
||||
- <hr>
|
||||
-
|
||||
- <form id="subscription-manager-form" class="sub-list-controls" method="POST">
|
||||
- {% if group_by_tags %}
|
||||
- <a class="sort-button" href="/https://www.youtube.com/subscription_manager?group_by_tags=0">Don't group</a>
|
||||
- {% else %}
|
||||
- <a class="sort-button" href="/https://www.youtube.com/subscription_manager?group_by_tags=1">Group by tags</a>
|
||||
- {% endif %}
|
||||
- <input type="text" name="tags">
|
||||
- <button type="submit" name="action" value="add_tags">Add tags</button>
|
||||
- <button type="submit" name="action" value="remove_tags">Remove tags</button>
|
||||
- <button type="submit" name="action" value="unsubscribe_verify">Unsubscribe</button>
|
||||
- <button type="submit" name="action" value="mute">Mute</button>
|
||||
- <button type="submit" name="action" value="unmute">Unmute</button>
|
||||
- <input type="reset" value="Clear Selection">
|
||||
- </form>
|
||||
-
|
||||
-
|
||||
- {% if group_by_tags %}
|
||||
- <ul class="tag-group-list">
|
||||
- {% for tag_name, sub_list in tag_groups %}
|
||||
- <li class="tag-group">
|
||||
- <h2 class="tag-group-name">{{ tag_name }}</h2>
|
||||
- <ol class="sub-list">
|
||||
- {{ subscription_list(sub_list) }}
|
||||
- </ol>
|
||||
- </li>
|
||||
- {% endfor %}
|
||||
- </ul>
|
||||
- {% else %}
|
||||
- <ol class="sub-list">
|
||||
- {{ subscription_list(sub_list) }}
|
||||
- </ol>
|
||||
- {% endif %}
|
||||
|
||||
{% endblock main %}
|
||||
diff --git a/youtube/templates/subscriptions.html b/youtube/templates/subscriptions.html
|
||||
index b528e5c..6302fcc 100644
|
||||
--- a/youtube/templates/subscriptions.html
|
||||
+++ b/youtube/templates/subscriptions.html
|
||||
@@ -13,71 +13,5 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
- <div class="subscriptions-sidebar">
|
||||
- <div class="sidebar-links">
|
||||
- <a class="sidebar-title" href="/youtube.com/subscription_manager" class="sub-manager-link">Subscription Manager</a>
|
||||
- <form class="sidebar-action" method="POST" class="refresh-all">
|
||||
- <input type="submit" value="Check All">
|
||||
- <input type="hidden" name="action" value="refresh">
|
||||
- <input type="hidden" name="type" value="all">
|
||||
- </form>
|
||||
- </div>
|
||||
-
|
||||
- <ol class="sidebar-list tags">
|
||||
- {% if current_tag %}
|
||||
- <li class="sidebar-list-item">
|
||||
- <a href="/youtube.com/subscriptions" class="sidebar-item-name">Any tag</a>
|
||||
- </li>
|
||||
- {% endif %}
|
||||
-
|
||||
- {% for tag in tags %}
|
||||
- <li class="sidebar-list-item">
|
||||
- {% if tag == current_tag %}
|
||||
- <span class="sidebar-item-name">{{ tag }}</span>
|
||||
- {% else %}
|
||||
- <a href="?tag={{ tag|urlencode }}" class="sidebar-item-name">{{ tag }}</a>
|
||||
- {% endif %}
|
||||
- <form method="POST" class="sidebar-item-refresh">
|
||||
- <input type="submit" value="Check">
|
||||
- <input type="hidden" name="action" value="refresh">
|
||||
- <input type="hidden" name="type" value="tag">
|
||||
- <input type="hidden" name="tag_name" value="{{ tag }}">
|
||||
- </form>
|
||||
- </li>
|
||||
- {% endfor %}
|
||||
- </ol>
|
||||
-
|
||||
- <hr>
|
||||
- <ol class="sidebar-list sub-refresh-list">
|
||||
- {% for subscription in subscription_list %}
|
||||
- <li class="sidebar-list-item {{ 'muted' if subscription['muted'] else '' }}">
|
||||
- <a href="{{ subscription['channel_url'] }}" class="sidebar-item-name" title="{{ subscription['channel_name'] }}">{{ subscription['channel_name'] }}</a>
|
||||
- <form method="POST" class="sidebar-item-refresh">
|
||||
- <input type="submit" value="Check">
|
||||
- <input type="hidden" name="action" value="refresh">
|
||||
- <input type="hidden" name="type" value="channel">
|
||||
- <input type="hidden" name="channel_id" value="{{ subscription['channel_id'] }}">
|
||||
- </form>
|
||||
- </li>
|
||||
- {% endfor %}
|
||||
- </ol>
|
||||
- </div>
|
||||
-
|
||||
- {% if current_tag %}
|
||||
- <h2 class="current-tag">{{ current_tag }}</h2>
|
||||
- {% endif %}
|
||||
-
|
||||
- <div class="video-container">
|
||||
- {% for video_info in videos %}
|
||||
- {{ common_elements.item(video_info) }}
|
||||
- {% endfor %}
|
||||
- </div>
|
||||
- <hr/>
|
||||
-
|
||||
- <footer class="pagination-container">
|
||||
- <nav class="pagination-list">
|
||||
- {{ common_elements.page_buttons(num_pages, '/youtube.com/subscriptions', parameters_dictionary) }}
|
||||
- </nav>
|
||||
- </footer>
|
||||
|
||||
{% endblock main %}
|
||||
diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html
|
||||
index 70f5692..9b55493 100644
|
||||
--- a/youtube/templates/watch.html
|
||||
+++ b/youtube/templates/watch.html
|
||||
@@ -79,8 +79,6 @@
|
||||
<script src="/youtube.com/static/js/speedyplay.js"></script>
|
||||
</div>
|
||||
|
||||
- <input class="v-checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
|
||||
-
|
||||
<details class="v-download">
|
||||
<summary class="download-dropdown-label">Download</summary>
|
||||
<ul class="download-dropdown-content">
|
||||
29
core/Dockerfile
Normal file
29
core/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM alpine:latest
|
||||
LABEL MAINTAINER="heckyel@riseup.net"
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ENV LC_ALL C.UTF-8
|
||||
|
||||
RUN apk add musl-dev build-base gcc libffi-dev python3-dev patch git py3-pip
|
||||
|
||||
ARG APP_DIR="/srv/app"
|
||||
ARG YT_REPO="https://git.sr.ht/~heckyel/yt-local"
|
||||
ARG YT_BRANCH="master"
|
||||
|
||||
RUN mkdir --parents "$APP_DIR"
|
||||
|
||||
WORKDIR "$APP_DIR"
|
||||
|
||||
RUN git clone --depth=1 "$YT_REPO" --branch "$YT_BRANCH" "$APP_DIR"
|
||||
RUN git show --oneline --no-patch
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
COPY 0001.patch "$APP_DIR/0001.patch"
|
||||
RUN patch -Np1 -i "$APP_DIR/0001.patch"
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
COPY entrypoint.sh /
|
||||
RUN chmod u+x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
80
core/entrypoint.sh
Normal file
80
core/entrypoint.sh
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Config
|
||||
if [ ! -d "/root/.youtube-local" ]; then
|
||||
# make dir
|
||||
install -d /root/.youtube-local
|
||||
|
||||
# generate config
|
||||
cat > /root/.youtube-local/settings.txt <<- EOF
|
||||
# 0 - Off
|
||||
# 1 - On, except video
|
||||
# 2 - On, including video (see warnings)
|
||||
route_tor = $ROUTE_TOR
|
||||
|
||||
tor_port = $TOR_PORT
|
||||
|
||||
tor_control_port = TOR_CONTROL_PORT
|
||||
|
||||
port_number = 8080
|
||||
|
||||
# This will allow others to connect to your Youtube Local instance as a website.
|
||||
# For security reasons, enabling this is not recommended.
|
||||
allow_foreign_addresses = $ALLOW_FOREIGN_ADDRESSES
|
||||
|
||||
# 0 - off by default
|
||||
# 1 - only manually created subtitles on by default
|
||||
# 2 - enable even if automatically generated is all that's available
|
||||
subtitles_mode = $SUBTITLES_MODE
|
||||
|
||||
# ISO 639 language code: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
subtitles_language = $SUBTITLES_LANG
|
||||
|
||||
# 0 - Related videos disabled
|
||||
# 1 - Related videos always shown
|
||||
# 2 - Related videos hidden; shown by clicking a button
|
||||
related_videos_mode = $RELATED_VIDEOS_MODE
|
||||
|
||||
# 0 - Video comments disabled
|
||||
# 1 - Video comments always shown
|
||||
# 2 - Video comments hidden; shown by clicking a button
|
||||
comments_mode = $COMMENTS_MODE
|
||||
|
||||
enable_comment_avatars = $ENABLE_COMMENTS_AVATARS
|
||||
|
||||
# 0 to sort by top
|
||||
# 1 to sort by newest
|
||||
default_comment_sorting = $DEFAULT_COMMENT_SORTING
|
||||
|
||||
theater_mode = $THEATER_MODE
|
||||
|
||||
default_resolution = $DEFAULT_RESOLUTION
|
||||
|
||||
use_video_hotkeys = $USE_VIDEO_HOTKEYS
|
||||
|
||||
proxy_images = $PROXY_IMAGES
|
||||
|
||||
use_comments_js = $USE_COMMENTS_JS
|
||||
|
||||
use_sponsorblock_js = $USE_SPONSORBLOCK_JS
|
||||
|
||||
theme = $THEME
|
||||
|
||||
font = $FONT
|
||||
|
||||
embed_page_mode = $EMBED_PAGE_MODE
|
||||
|
||||
autocheck_subscriptions = $AUTOCHECK_SUBSCRIPTIONS
|
||||
|
||||
# Developer use to debug 403s
|
||||
gather_googlevideo_domains = $GATHER_GOOGLEVIDEO_DOMAINS
|
||||
|
||||
# Save all responses from youtube for debugging
|
||||
debugging_save_responses = $DEBUGGING_SAVE_RESPONSES
|
||||
|
||||
# Do not change, remove, or comment out this value, or else your settings may be lost or corrupted
|
||||
settings_version = 3
|
||||
EOF
|
||||
fi
|
||||
|
||||
exec /usr/bin/python3 /srv/app/server.py
|
||||
Reference in New Issue
Block a user