Esempio n. 1
0
def get_unlisted_livestreams_by_username(username: str) -> Dict[str, Any]:
    """Get a user's unlisted livestreams from their username.

    Args:
        username (str): The user's username.

    Returns:
        Dict[str, Any]: The unlisted livestream.
    """
    items = "user_snowflake, start_date, title, description, category, unique_id"
    res = query_one("SELECT snowflake FROM user WHERE username = ?",
                    [username])
    stream = query_one(
        f"SELECT {items} FROM stream WHERE user_snowflake = ? AND unlisted = 1 AND end_date IS NULL AND start_date IS NOT NULL",  # noqa: E501
        [res["snowflake"]],
    )
    if stream:
        stream["username"] = username
    return stream
Esempio n. 2
0
def get_livestreams_by_username(username: str) -> Dict[str, Any]:
    """Get a user's current livestreams via their username.

    Args:
        username (str): The username you want to check for.

    Returns:
        Dict[str, Any]: The livestream's details.
    """
    items = "user_snowflake, start_date, title, description, category, unique_id"
    user_id = query_one("SELECT snowflake FROM user WHERE username = ?",
                        [username])
    stream = query_one(
        f"SELECT {items} FROM stream WHERE user_snowflake = ? AND unlisted = 0 AND end_date IS NULL AND start_date IS NOT NULL",  # noqa: E501
        [user_id["snowflake"]],
    )
    if stream:
        stream["username"] = username
    return stream
Esempio n. 3
0
def get_unique_stream_id_from_stream_key(stream_key: str) -> str:
    """Get a stream's unique ID from its key.

    Args:
        stream_key (str): The stream's key

    Returns:
        str: The unique ID.
    """
    res = query_one("SELECT unique_id FROM stream WHERE stream_key = ?",
                    [stream_key])
    return res["unique_id"]
Esempio n. 4
0
def get_stream_key_from_unique_id(unique_id: str) -> str:
    """Get a stream's stream key from its unique ID.

    Args:
        unique_id (str): The stream's unique ID.

    Returns:
        str: The stream key.
    """
    res = query_one("SELECT stream_key FROM stream WHERE unique_id = ?",
                    [unique_id])
    return res["stream_key"]
Esempio n. 5
0
def end_stream(stream_key: str) -> None:
    """Sets the stream's end date in the database.

    Args:
        stream_key (str): The stream key to update.
    """
    db = get_db()
    current_app.logger.info(f"Ending stream {stream_key}")
    res = query_one("SELECT * FROM stream WHERE stream_key = ?", [stream_key])
    db.execute(
        "UPDATE stream SET end_date = ? WHERE id = ?",
        (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), res["id"]),
    )
    db.commit()
Esempio n. 6
0
def get_username_from_snowflake(snowflake: int) -> str:
    """Get a user's username from a user ID.

    Args:
        snowflake (int): The user's ID.

    Returns:
        str: The user's username.
    """
    user = query_one(
        "SELECT username FROM user WHERE snowflake = ?",
        [snowflake],
    )
    return user["username"]
Esempio n. 7
0
def manage_stream(unique_id: str) -> Any:
    """Manage a stream's properties via its unique ID. 

    Args:
        unique_id (str): The stream's unique ID.

    Returns:
        Any: A static page rendered by Flask.
    """
    user = discord.fetch_user()
    form = StreamGenerationForm()
    stream = query_one(
        "SELECT title, description, category, archivable, unlisted, user_snowflake FROM stream WHERE unique_id = ?",
        [unique_id],
    )

    if not stream:
        return render_template("alert.html", error="Invalid stream ID."), 404

    # Populate the stream editing form.
    form.title.data = stream["title"]
    form.description.data = stream["description"]
    form.category.data = stream["category"]
    form.archivable.data = stream["archivable"]
    form.unlisted.data = stream["unlisted"]

    if stream["user_snowflake"] == user.id:
        if request.method == "GET":
            return render_template("manage_stream.html",
                                   form=form,
                                   unique_id=unique_id)

        if request.method == "POST":
            form = StreamGenerationForm(request.form)
            if form.validate():
                keys_to_change = {}
                for key, value in form.data.items():
                    if stream[key] != value:
                        keys_to_change[key] = value
                update_db_fields(unique_id, **keys_to_change)
                return render_template("manage_stream.html",
                                       form=form,
                                       unique_id=unique_id,
                                       update=True)
    else:
        # User does not have access to manage this stream ID.
        return abort(403)
Esempio n. 8
0
def done() -> Any:
    """Mark the stream as done and archive the stream.

    Returns:
        Any: Returns 200 when the function has completed.
    """
    stream_key = request.form["name"]
    end_stream(stream_key)

    stream = query_one("SELECT * FROM stream WHERE stream_key = ?",
                       [stream_key])
    if bool(stream["archivable"]):
        current_app.logger.info("Stream is archivable.")
    else:
        current_app.logger.info("Stream is going to be archived privately.")

    archive_stream(stream_key)
    return jsonify({"message": "Stream has successfully ended"}), 200
Esempio n. 9
0
def verify_stream_key(stream_key: str) -> bool:
    """Validate that the stream key exists in the database

    Args:
        stream_key (str): The stream key to validate.

    Returns:
        bool: True if the key exists.
    """
    valid = False
    res = query_one(
        "SELECT * from stream WHERE stream_key = ? AND end_date IS NULL",
        [stream_key])
    try:
        if res["stream_key"]:
            current_app.logger.info(f"Accepting stream: {stream_key}")
            valid = True
    except TypeError:
        current_app.logger.info(f"Invalid stream key: {stream_key}")

    return valid
Esempio n. 10
0
def me() -> Text:
    """Render a page to manage stream properties

    Returns:
        Text: Static page rendered by Flask.
    """
    discord_user = discord.fetch_user()
    user = query_one("SELECT * FROM user WHERE snowflake = ?", [discord_user.id])
    streams = query_many(
        "SELECT * FROM stream WHERE user_snowflake = ?", [discord_user.id]
    )
    if streams:
        for stream in streams:
            try:
                duration = stream["end_date"] - stream["start_date"]
                stream["duration"] = str(duration)
            except TypeError:
                continue
            stream["username"] = user["username"]
        return render_template("manage_user.html", user=user, streams=streams)

    return render_template("manage_user.html", user=user)
Esempio n. 11
0
def serve_stream(unique_id: str, file: str) -> Any:
    """Serve stream via its unique ID

    Example:
    A stream uses the following IDs and keys:
    Stream key = 1451fgsa
    Unique ID = klzfls156

    GET /watch/klzfls156/index.m3u8
    < HLS_DIR/1451fgsa-index.m3u8

    GET /watch/klzfls156/1.ts
    < HLS_DIR/1451fgsa-1.ts

    Args:
        unique_id (str): The stream's unique ID
        file (str): The requested file

    Returns:
        Any: Serves file from HLS path if exists.
    """
    stream_key = get_stream_key_from_unique_id(unique_id)
    stream = query_one("SELECT end_date FROM stream WHERE stream_key = ?", [stream_key])
    if stream_key and not stream["end_date"]:
        if file == "index.m3u8":
            try:
                rewrite_stream_playlist(stream_key)
                return send_from_directory(
                    environ.get("HLS_PATH"), f"{stream_key}-index.m3u8"
                )
            except FileNotFoundError:
                return abort(404)
        else:
            return send_from_directory(environ.get("HLS_PATH"), f"{stream_key}-{file}")

    return abort(404)
Esempio n. 12
0
def serve_archive(unique_id: str) -> Response:
    """Serves stream from the archive.

    Args:
        unique_id (str): The stream's unique ID.

    Returns:
        Response: File being served by Flask's Response class.
    """
    user = discord.fetch_user()
    stream = query_one(
        "SELECT * FROM stream WHERE archived_file IS NOT NULL AND unique_id = ?",
        [unique_id],
    )
    if user.id == stream["user_snowflake"]:
        # The user requesting the stream created it.
        # Therefore they shall always have access to the file.
        return serve_file(stream)
    elif bool(stream["archivable"]):
        # The stream is publically archived.
        return serve_file(stream)
    else:
        # The stream does not exist.
        return abort(404)