Skip to content

Instantly share code, notes, and snippets.

@S1M0N38
Created August 23, 2022 10:19
Show Gist options
  • Save S1M0N38/7f8ca02279447ea3ed8529a450e61c11 to your computer and use it in GitHub Desktop.
Save S1M0N38/7f8ca02279447ea3ed8529a450e61c11 to your computer and use it in GitHub Desktop.
Expose acestreams from morningstream in you local network
#!/usr/bin/env python3
"""
This content is not affiliated with, endorsed, sponsored, or specifically
approved by Morningstreams.
This is the simple script from where
https://github.com/S1M0N38/morningstreams originates.
MIT License
Copyright (c) 2021 S1M0N38
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.
"""
import argparse
import json
import os
import socketserver
from http import client, server
from urllib import error, request
# Arguments parsing
parser = argparse.ArgumentParser(
description="Expose acestreams from morningstreams in you local network.",
epilog="Source code: https://github.com/S1M0N38/morningstreams",
)
parser.add_argument(
"--ip",
default="127.0.0.1",
help="ip where the m3u8 will be exposed",
)
parser.add_argument(
"--port",
default=8080,
help="port where the m3u8 will be exposed",
)
parser.add_argument(
"--mpv",
action="store_true",
help="open streams with mpv",
)
parser.add_argument(
"--username",
default=os.getenv("MORNINGSTREAMS_USERNAME"),
help="your morningstreams username",
)
parser.add_argument(
"--password",
default=os.getenv("MORNINGSTREAMS_PASSWORD"),
help="your morningstreams password",
)
args = parser.parse_args()
# Check if username and password are set
if not args.username or not args.password:
raise ValueError(
"""
morningstreams credentials are not provided.
Used the flags --username and --password or
export MORNINGSTREAMS_USERNAME and MORNINGSTREAMS_PASSWORD
environment variables."""
)
# Check if ACE stream Engine is running
try:
request.urlopen(f"http://{args.ip}:6878/webui/api/service")
except error.URLError:
raise EnvironmentError("ACE stream engine is not running.")
# Login Morningstreams
conn = client.HTTPSConnection("api.morningstreams.com")
credentials = {
"username": args.username,
"password": args.password,
}
headers = {"Content-type": "application/json"}
conn.request("POST", "/api/auth/login", json.dumps(credentials), headers)
response = conn.getresponse()
token = json.loads(response.read().decode("utf-8"))["token"]
headers = {"authorization": f"bearer {token}"}
print(f"\nLogged in as {args.username} βœ“")
# ACE Stream
conn.request("GET", "/api/acestreams", headers=headers)
response = conn.getresponse()
streams = json.loads(response.read().decode("utf-8"))
print(f"\nFound {len(streams)} streams:")
for stream in streams:
print(f" - {stream['title']} πŸ‘ {stream['likesCount']}")
conn.close()
# Save links in m3u8 file
m3u8 = "#EXTM3U\n"
for link in streams:
try:
int(link["contentId"], 16) # check if is a acestream link
m3u8 += f'#EXTINF:-1,{link["title"]}\n'
m3u8 += f'http://{args.ip}:6878/ace/getstream?id={link["contentId"]}\n'
except ValueError:
pass
with open("playlist.m3u8", "w") as f:
f.write(m3u8)
# Spawn http server
address = ("", args.port)
url = f"http://{args.ip}:{args.port}/playlist.m3u8"
httpd = socketserver.TCPServer(address, server.SimpleHTTPRequestHandler)
print(f"\nStarting httpd at {url}")
print("Press Ctrl+C to stop the server.")
try:
if args.mpv:
options = """\
--no-resume-playback\
--rebase-start-time=no\
--cache=no\
--cache-pause-wait=3\
--audio-buffer=0\
--stream-buffer-size=4k\
--pause=no\
"""
print("Opening streams with mpv ...")
os.system(f"mpv {options} playlist.m3u8")
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
print("\nStopping httpd...")
@S1M0N38
Copy link
Author

S1M0N38 commented Aug 23, 2022

morningstreams

Sometimes I want to watch acestream on my computer and sometimes on my TV
(with LG WebOS) so I came up with the following solution which suited to both
circumstances.

┏━━━━━━━━━━━━━━━━━━━━━━━━━f1.py━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                        ┃
┃                                      GET acestream ids ┃
┃                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‹β”€β”€β”€β”€β”€β–Άβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
┃                       β”‚   client    β”‚                  ┃      β”‚ api.morningstreams.com β”‚
┃                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β—€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‹β”€β”€β”€β”€β”€β”€β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
┃                              β”‚       acestream ids     ┃
┃                              β”‚                         ┃
┃                    generate playlist                   ┃
┃                          β”‚                             ┃GET playlist.m3u8
┃ serverβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β—€β”€β”€β”€β•‹β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
┃ β”‚                        β–Ό                        β”‚    ┃                 β”‚ video player β”‚
┃ β”‚ ┏━playlist.m3u8━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ β”‚β”€β”€β”€β”€β•‹β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
┃ β”‚ ┃ #EXTM3U                                     ┃ β”‚    ┃playlist.m3u8                   β–²
┃ β”‚ ┃ #EXTINF:-1, Server 1                        ┃ β”‚    ┃                        stream  β”‚
┃ β”‚ ┃ http://[--ip]:[--port]/ace/getstream?id=13f…┃ β”‚    ┃                                β”‚
┃ β”‚ ┃ #EXTINF:-1, Server 2 (backup)               ┃ β”‚    ┃ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
┃ β”‚ ┃ http://[--ip]:[--port]/ace/getstream?id=3e8…┃ β”‚    ┃ β”‚    acestream engine    β”‚     β”‚
┃ β”‚ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ β”‚    ┃ β”‚   (wrapped in docker   β”‚     β”‚
┃ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    ┃ β”‚container if necessary) β”‚β—€β”€β”€β”€β”€β”˜
┃                                                        ┃ β”‚                        β”‚
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Requirements

  • moringstreams account
  • Docker desktop installed
  • python3 installed
  • computer with static LAN IP (mine is 192.168.178.100) connect with Ethernet.

Morningstreams account credentials are used to get acestream links.
Credendials can be set as enviroment variables, e.g. in your .bashrc

export MORNINGSTREAMS_USERNAME="my_username"
export MORNINGSTREAMS_PASSWORD="my_password"

or passed as arguments while running the script:

python3 f1.py --username "my_username" --password "my_password"

Docker is the simplest way to run acestream Engine on Mac OS.
Python3 is used as scripting language to make requests to morningstreams API and
to spawn a simple server where to serve acestream links to your local network.

My setup

This is my setup so it won't be your ideal setup; nevertheless it could
inspire you on how to develop your own.

  1. Acestream Engine is running on my computer inside to
    magnetikonline/acestream-server container. To run this I use the following
    alias:

    alias ace="docker run --publish 6878:6878 --rm --tmpfs \
              '/dev/disk/by-id:noexec,rw,size=4k' \
              magnetikonline/acestream-server"
  2. Then, from inside this repository, I run

    python3 f1.py --ip 192.168.178.100

    This script requests to morningstreams API acestreams link available and
    organize write them in playlist.m3u8 file. Then a simple http is spawned so
    playlist.m3u8 is shared across your local network. You can now see this file
    with all your devices (including your TV) connect to your local network by
    visiting http://192.168.178.100:8080/playlist.m3u8 (of course this address
    depends on your computer local IP).

Watch streams

  • Computer: use a player with HSL support to open
    http://192.168.178.100:8080/playlist.m3u8.

  • TV (LG WebOS): use F-Player to open
    http://192.168.178.100:8080/playlist.m3u8.


pro-tip: to see all the arguemnts of f1.py script run

python3 f1.py --help

pro-tip: if you just watch the stream on the same computer which is running
the acestream engine and mpv is installed, simply use

python3 f1.py --mpv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment