first commit
This commit is contained in:
124
.gitignore
vendored
Normal file
124
.gitignore
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
.vscode/
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
FROM ubuntu:18.04 as builder
|
||||||
|
|
||||||
|
ARG VERSION="3.1.49_ubuntu_18.04"
|
||||||
|
RUN apt-get update &&\
|
||||||
|
apt-get install --no-install-recommends --yes wget && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm --force --recursive /var/lib/apt/lists
|
||||||
|
RUN mkdir /opt/acestream && \
|
||||||
|
wget --no-check-certificate -O- "https://download.acestream.media/linux/acestream_3.1.49_ubuntu_18.04_x86_64.tar.gz" | \
|
||||||
|
tar -xz -C /opt/acestream
|
||||||
|
|
||||||
|
# actual image
|
||||||
|
FROM ubuntu:18.04
|
||||||
|
LABEL maintainer="Jack Liar <zhigu1017@gmail.com>"
|
||||||
|
RUN apt-get update --yes && \
|
||||||
|
apt-get install --no-install-recommends --yes \
|
||||||
|
apt-utils python-setuptools python-m2crypto python-apsw libpython2.7 libssl1.0.0 net-tools libxslt1.1 && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm --force --recursive /var/lib/apt/lists
|
||||||
|
COPY --from=builder /opt/acestream /opt/acestream
|
||||||
|
|
||||||
|
EXPOSE 6878
|
||||||
|
|
||||||
|
ENV ACESTREAM_ROOT="/opt/acestream"
|
||||||
|
ENV LD_LIBRARY_PATH="${ACESTREAM_ROOT}/lib"
|
||||||
|
|
||||||
|
CMD ["/opt/acestream/acestreamengine", "--client-console"]
|
||||||
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2019 Jack Liar(https://github.com/JackLiar)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
84
README.md
Normal file
84
README.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Docker Ace Stream server
|
||||||
|
An [Ace Stream](http://www.acestream.org/) server Docker image & Python3 client to stream.
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Reference](#reference)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
What this provides:
|
||||||
|
- Dockerized Ace Stream server (version `3.1.35`) running under Ubuntu 18.04.
|
||||||
|
- Bash script to start server and present HTTP API endpoint to host.
|
||||||
|
- Python playback script [`playstream.py`](playstream.py) instructing server to:
|
||||||
|
- Commence streaming of a given content ID.
|
||||||
|
- ...and optionally start a compatible media player (such as [iina(OS X only)](https://iina.io/)) to view stream.
|
||||||
|
|
||||||
|
Since a single HTTP endpoint exposed from the Docker container controls the server _and_ provides the output stream, this provides one of the easier methods for playback of Ace Streams on traditionally unsupported operating systems such as OS X.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
To build Docker image:
|
||||||
|
```sh
|
||||||
|
$ ./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Start the server via:
|
||||||
|
```sh
|
||||||
|
$ ./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Server will now be available from `http://127.0.0.1:6878`:
|
||||||
|
```sh
|
||||||
|
$ curl http://127.0.0.1:6878/webui/api/service?method=get_version&format=jsonp&callback=
|
||||||
|
# {"result": {"code": 3013500, "platform": "linux", "version": "3.1.35"}, "error": null}
|
||||||
|
```
|
||||||
|
|
||||||
|
A program ID can be started with [`playstream.py`](playstream.py):
|
||||||
|
```sh
|
||||||
|
$ ./playstream.py --help
|
||||||
|
usage: playstream.py [-h] --content-id HASH [--player PLAYER]
|
||||||
|
[--server HOSTNAME] [--port PORT] [--multi-players] [-d]
|
||||||
|
|
||||||
|
Instructs server to commence a given content ID. Will execute a local media
|
||||||
|
player once playback has started.
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
--content-id HASH content ID to stream
|
||||||
|
--player PLAYER media player to execute once stream active
|
||||||
|
--server HOSTNAME server hostname, defaults to 127.0.0.1
|
||||||
|
--port PORT server HTTP API port, defaults to 6878
|
||||||
|
--multi-players play stream in multiple players mode, defaults to False
|
||||||
|
-d, --debug run client in debug mode
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, to stream `CONTENT_ID` and send playback to `iina` when ready:
|
||||||
|
```sh
|
||||||
|
$ ./playstream.py \
|
||||||
|
--content-id CONTENT_ID \
|
||||||
|
--player /usr/bin/vlc \
|
||||||
|
|
||||||
|
INFO 2019-05-12 18:45:52,190 playstream.py 47 Client starts.
|
||||||
|
INFO 2019-05-12 18:45:52,202 playstream.py 91 acestream engine version: 3.1.35
|
||||||
|
INFO 2019-05-12 18:45:52,202 playstream.py 93 acestream engine version code: 3013500
|
||||||
|
INFO 2019-05-12 18:45:52,202 playstream.py 188 Acestream server is available
|
||||||
|
Status: | Peers: 0 | Down: 0KB/s | Up: 0KB/s
|
||||||
|
Status: prebuf | Peers: 0 | Down: 0KB/s | Up: 0KB/s
|
||||||
|
Status: prebuf | Peers: 4 | Down: 24KB/s | Up: 0KB/s
|
||||||
|
Status: prebuf | Peers: 4 | Down: 540KB/s | Up: 0KB/s
|
||||||
|
Status: dl | Peers: 4 | Down: 887KB/s | Up: 0KB/s
|
||||||
|
Status: dl | Peers: 4 | Down: 957KB/s | Up: 0KB/s
|
||||||
|
Status: dl | Peers: 4 | Down: 887KB/s | Up: 0KB/s
|
||||||
|
Status: dl | Peers: 4 | Down: 870KB/s | Up: 1KB/s
|
||||||
|
Status: dl | Peers: 4 | Down: 828KB/s | Up: 2KB/s
|
||||||
|
INFO 2019-05-10 19:31:23,590 playstream3.py 57 Client exit.
|
||||||
|
```
|
||||||
|
|
||||||
|
Send <kbd>Ctrl + C</kbd> to exit.
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
- [Ace Stream Wiki (English)](http://wiki.acestream.org/wiki/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0/en).
|
||||||
|
- Binary downloads: http://wiki.acestream.org/wiki/index.php/Download.
|
||||||
|
- Ubuntu install notes: http://wiki.acestream.org/wiki/index.php/Install_Ubuntu.
|
||||||
|
- HTTP API usage: http://wiki.acestream.org/wiki/index.php/Engine_HTTP_API.
|
||||||
|
- `playstream.py` routines inspired by: https://github.com/magnetikonline/docker-acestream-server.
|
||||||
9
build.sh
Executable file
9
build.sh
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
DIRNAME=$(dirname "$0")
|
||||||
|
DOCKER_IMAGE_NAME="jackwzh/acestream-server"
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--tag "$DOCKER_IMAGE_NAME" \
|
||||||
|
--force-rm \
|
||||||
|
"$DIRNAME"
|
||||||
279
playstream.py
Executable file
279
playstream.py
Executable file
@@ -0,0 +1,279 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
# File: /playstream3.py
|
||||||
|
# Created Date: Monday April 29th 2019
|
||||||
|
# -----
|
||||||
|
# Last Modified: Sunday May 12th 2019 7:22:55 pm
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.request
|
||||||
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class Client(object):
|
||||||
|
|
||||||
|
def __init__(self, server_host, server_port, multi_players=False):
|
||||||
|
self.server_host = server_host
|
||||||
|
self.server_port = server_port
|
||||||
|
|
||||||
|
self.engine_version = ""
|
||||||
|
self.engine_version_code = 0
|
||||||
|
|
||||||
|
self.multi_players = multi_players
|
||||||
|
self.poll_time = 2
|
||||||
|
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
|
||||||
|
def stop(sig_num, stack_frame):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
self.running = True
|
||||||
|
logging.info("Client starts.")
|
||||||
|
signal.signal(signal.SIGINT, stop)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type=None, exc_value=None, traceback=None):
|
||||||
|
if any([exc_type, exc_value, traceback]):
|
||||||
|
logging.error(repr(exc_type))
|
||||||
|
logging.error(repr(exc_value))
|
||||||
|
logging.error(repr(traceback))
|
||||||
|
logging.info("Client exit.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _api_request(self, url: str) -> Dict:
|
||||||
|
"""Send request to acestream server and return response json dict
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: api url
|
||||||
|
Returns:
|
||||||
|
dict: response json data
|
||||||
|
"""
|
||||||
|
response = urllib.request.urlopen(url)
|
||||||
|
return json.loads(response.read().decode())
|
||||||
|
|
||||||
|
def _check_server_availability(self) -> bool:
|
||||||
|
"""Check server availability before start streaming
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: wether server is avaliable
|
||||||
|
"""
|
||||||
|
url = "http://{}:{}/webui/api/service?method=get_version&format=jsonp&callback=".format(
|
||||||
|
self.server_host, self.server_port)
|
||||||
|
try:
|
||||||
|
response_dic = self._api_request(url)
|
||||||
|
except:
|
||||||
|
logging.exception("Check server availability failed!")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if response_dic.get("error"):
|
||||||
|
return False
|
||||||
|
self.engine_version = response_dic.get("result").get("version")
|
||||||
|
self.engine_version_code = int(
|
||||||
|
response_dic.get("result").get("code"))
|
||||||
|
|
||||||
|
logging.info("acestream engine version: {}".format(
|
||||||
|
self.engine_version))
|
||||||
|
logging.info("acestream engine version code: {}".format(
|
||||||
|
self.engine_version_code))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def start_streaming(self, content_id: str) -> Tuple[str, str]:
|
||||||
|
"""Start streaming content ID
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content_id: acestream content ID
|
||||||
|
Returns:
|
||||||
|
playback_url: playback url for media player to stream
|
||||||
|
stat_url: stat url for client to get stat info of acestream engine
|
||||||
|
"""
|
||||||
|
if self.multi_players:
|
||||||
|
# generate a player id to support multi players playing
|
||||||
|
player_id = hashlib.sha1(content_id.encode()).hexdigest()
|
||||||
|
url = 'http://{}:{}/ace/getstream?format=json&id={}&pid={}'.format(
|
||||||
|
self.server_host, self.server_port, content_id, player_id)
|
||||||
|
else:
|
||||||
|
url = 'http://{}:{}/ace/getstream?format=json&id={}'.format(
|
||||||
|
self.server_host, self.server_port, content_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response_dic = self._api_request(url)
|
||||||
|
except:
|
||||||
|
logging.exception(
|
||||||
|
"Parsing server http response failed while starting streaming!"
|
||||||
|
)
|
||||||
|
return "", ""
|
||||||
|
else:
|
||||||
|
playback_url = response_dic.get('response').get("playback_url")
|
||||||
|
stat_url = response_dic.get('response').get("stat_url")
|
||||||
|
return playback_url, stat_url
|
||||||
|
|
||||||
|
def _start_media_player(self, media_player: str,
|
||||||
|
playback_url: str) -> bool:
|
||||||
|
"""Start media to get stream from acestream server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
media_player: media player cli program name
|
||||||
|
playback_url: acestream server playback url
|
||||||
|
Return:
|
||||||
|
bool: whether media player stared successfully
|
||||||
|
"""
|
||||||
|
# change this if the predefined command is not suitable for your player
|
||||||
|
cmd = [media_player, playback_url]
|
||||||
|
|
||||||
|
try:
|
||||||
|
process = subprocess.run(cmd)
|
||||||
|
process.check_returncode()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
logging.exception("{} didn't exit normally!".format(media_player))
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _monitor_stream_status(self, stat_url: str) -> None:
|
||||||
|
"""Keep monitor stream stat status
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stat_url: acestream server stat url
|
||||||
|
"""
|
||||||
|
|
||||||
|
def stream_stats_message(response: dict) -> str:
|
||||||
|
return 'Status: {} | Peers: {:>3} | Down: {:>4}KB/s | Up: {:>4}KB/s'.format(
|
||||||
|
response.get('response', {
|
||||||
|
'status': 0
|
||||||
|
}).get('status', ""),
|
||||||
|
response.get('response', {
|
||||||
|
'peers': 0
|
||||||
|
}).get('peers', 0),
|
||||||
|
response.get('response', {
|
||||||
|
'speed_down': 0
|
||||||
|
}).get('speed_down', 0),
|
||||||
|
response.get('response', {
|
||||||
|
'speed_up': 0
|
||||||
|
}).get('speed_up', 0))
|
||||||
|
|
||||||
|
while (self.running):
|
||||||
|
print(stream_stats_message(self._api_request(stat_url)))
|
||||||
|
|
||||||
|
time.sleep(self.poll_time)
|
||||||
|
|
||||||
|
def run(self, content_id: str, media_player: str) -> bool:
|
||||||
|
"""A simplified api for running whole process easily
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content_id: acestream content ID
|
||||||
|
media_player: media player to play the stream
|
||||||
|
Returns:
|
||||||
|
bool: whether client run successfully
|
||||||
|
"""
|
||||||
|
if not self._check_server_availability():
|
||||||
|
logging.error(
|
||||||
|
"Server is not available. Please check server status")
|
||||||
|
return False
|
||||||
|
logging.info("Acestream server is available")
|
||||||
|
|
||||||
|
playback_url, stat_url = self.start_streaming(content_id)
|
||||||
|
if not playback_url or not stat_url:
|
||||||
|
return False
|
||||||
|
logging.debug("Server playback url: {}".format(playback_url))
|
||||||
|
logging.debug("Server stat url: {}".format(stat_url))
|
||||||
|
|
||||||
|
if not self._start_media_player(media_player, playback_url):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._monitor_stream_status(stat_url)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_SERVER_HOSTNAME = '127.0.0.1'
|
||||||
|
DEFAULT_SERVER_PORT = 6878
|
||||||
|
DEFAULT_MEDIA_PLAYER = "iina"
|
||||||
|
SERVER_POLL_TIME = 2
|
||||||
|
SERVER_STATUS_STREAM_ACTIVE = 'dl'
|
||||||
|
FORMAT = '%(levelname)s %(asctime)-15s %(filename)s %(lineno)-8s %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
"""Parse comand line arguments
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.Namespace: command line args
|
||||||
|
"""
|
||||||
|
# create parser
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Instructs server to commence a given content ID. '
|
||||||
|
'Will execute a local media player once playback has started.')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--content-id',
|
||||||
|
help='content ID to stream',
|
||||||
|
metavar='HASH',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--player',
|
||||||
|
help='media player to execute once stream active',
|
||||||
|
default=DEFAULT_MEDIA_PLAYER,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--server',
|
||||||
|
default=DEFAULT_SERVER_HOSTNAME,
|
||||||
|
help='server hostname, defaults to %(default)s',
|
||||||
|
metavar='HOSTNAME',
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--port',
|
||||||
|
default=DEFAULT_SERVER_PORT,
|
||||||
|
help='server HTTP API port, defaults to %(default)s',
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--multi-players',
|
||||||
|
action="store_true",
|
||||||
|
help='play stream in multiple players mode, defaults to %(default)s',
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-d',
|
||||||
|
'--debug',
|
||||||
|
action="store_true",
|
||||||
|
help='run client in debug mode',
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not re.match(r'^[a-f0-9]{40}$', args.content_id):
|
||||||
|
# if content id is not a valid hash, quit program
|
||||||
|
logging.error('Invalid content ID: [{}]'.format(args.content_id))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(format=FORMAT, level=logging.INFO)
|
||||||
|
|
||||||
|
with Client(args.server, args.port) as client:
|
||||||
|
client.run(args.content_id, args.player)
|
||||||
13
run.sh
Executable file
13
run.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
DOCKER_IMAGE_NAME="jackwzh/acestream-server"
|
||||||
|
SERVER_HTTP_PORT="6878"
|
||||||
|
|
||||||
|
docker run \
|
||||||
|
--name ace-server \
|
||||||
|
--publish "$SERVER_HTTP_PORT:$SERVER_HTTP_PORT" \
|
||||||
|
-p 8621:8621 \
|
||||||
|
--rm \
|
||||||
|
--mount type=tmpfs,target=/dev/disk/by-id,tmpfs-mode=660,tmpfs-size=4k \
|
||||||
|
--mount type=tmpfs,target=/root/.ACEStream,tmpfs-mode=660,tmpfs-size=8192m \
|
||||||
|
"$DOCKER_IMAGE_NAME"
|
||||||
Reference in New Issue
Block a user