twinx

package module
v0.0.0-...-b4eff69 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2021 License: Apache-2.0 Imports: 24 Imported by: 0

README

twinx

  ████████╗██╗    ██╗██╗███╗   ██╗██╗  ██╗
  ╚══██╔══╝██║    ██║██║████╗  ██║╚██╗██╔╝
     ██║   ██║ █╗ ██║██║██╔██╗ ██║ ╚███╔╝
     ██║   ██║███╗██║██║██║╚██╗██║ ██╔██╗
     ██║   ╚███╔███╔╝██║██║ ╚████║██╔╝ ██╗
     ╚═╝    ╚══╝╚══╝ ╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝

twinx is a live-streaming command line tool for Linux. It connects streaming services (like Twitch, OBS and YouTube) together via a common title and description.

Overview

Use twinx to manage your streams. This should be the first and last tool you use while live-streaming. This will kick off a persistent standalone linux process that runs as a temporary daemon for the duration of the stream. The daemon can then be interfaced with using the twinx command line tool. You can add integrations and functionality to your stream after it has been started.

Example

Use twinx to start a new stream on a Linux filesystem. This will register your title and description for your new stream, and start the background process. The title and description will be used as we work with various backends.

$ # twinx stream start <title> <description>
$ twinx stream start \
    "How to hack the planet" \
    "This is a live stream about how to hack the kernel to burn down capitalism"

Start an RTMP server. If no host:port is defined, twinx will select a port and listen on localhost:1935.

$ twinx rtmp start <optional host:port>
$ twinx rtmp start localhost:1719

Send the local stream to a remote backend such as Twitch or YouTube Live via the proxy command. You may proxy to multiple backends 🙂 at the same time.

# Example Twitch
$ twinx rtmp proxy rtmp://jfk.contribute.live-video.net/app/{stream_key}

# Example YouTube
$ twinx rtmp proxy rtmp://a.rtmp.youtube.com/live2/{stream_key}

Configuration

Twitch Callback URL Port: 1717

Environmental Variables

# OBS
export TWINX_OBS_PORT="1718"
export TWINX_OBS_PASSWORD=""
export TWINX_OBS_HOST="localhost"

# YouTube
export TWINX_YOUTUBE_API_KEY=""

Permissions

twinx will manage RTMP servers, unix sockets, and gRPC servers and clients for you. twinx requires root privileges to do this.

FAQ

This tool is a reflection of being asked the following questions

What are you working on today? Where is that video you did on What is this stream even about?

Installing

Build the binary.

Install the binary.

./configure
make
sudo make install

Arch Linux dependencies

Note: We use nginx-rtmp instead of the module based package combinations.

protoc-gen-go protoc-gen-go-grpc
nginx-rtmp
RTMP Protocol Reference

Documentation

Index

Constants

View Source
const (
	ActiveStreamPID string = "/var/run/twinx.pid"
	ActiveStreamLog string = "/var/log/twinx.log"
)
View Source
const (
	ActiveStreamPIDWriteMode os.FileMode = 0600
	ActiveStreamSocket                   = "/var/run/twinx.sock"
	ActiveStreamRTMPHost                 = "localhost"
)
View Source
const (
	ENVAR_OBSPort     = "TWINX_OBS_PORT"
	ENVAR_OBSPassword = "TWINX_OBS_PASSWORD"
	ENVAR_OBSHost     = "TWINX_OBS_HOST"
)
View Source
const (
	TWINX_PUBLIC_ID           string = "ykiaywwbve0aa3vm15cruou06dpuct"
	TWINX_PUBLIC_CALLBACK_URL string = "http://localhost:1717"
)
View Source
const (
	// OpenCommand is linux specific
	OpenCommand = "xdg-open"

	// LocalhostListenPort will listen onport 1717 for requests
	LocalhostListenPort = "1717"
)
View Source
const (
	NivenlyDefaultPageHeader string = "Access-Control-Allow-Origin: *"

	// NivenlyDefaultPageTemplate
	// 4 string substitutions
	//   1. Title
	//   2. Main text
	//   3. Sub 1
	//   4. Sub 2
	NivenlyDefaultPageTemplate string = `` /* 12715-byte string literal not displayed */

)
View Source
const (
	ENVAR_YouTubeAPIKey = "TWINX_YOUTUBE_API_KEY"
)

Variables

View Source
var Browsers = []string{"/usr/bin/brave", "/usr/bin/firefox", "/usr/bin/google-chrome-stable"}

Browsers are default browser executables (in order) to try and use on Linux. taken from my personal Archlinux setup.

Please feel free to add these, but do not change the order as they are important to me!

View Source
var CompileFlagPrintBanner bool = true

CompileFlagPrintBanner will enable/disable the banner for the program.

View Source
var CompileTimeVersion string

CompileTimeVersion is set at compile time in the associated Makefile Do not change this!

View Source
var TwitchPermissions = []string{

	"user:read:email",
}

TwitchPermissions is what we ask for in oAuth

These are very invasive, so please deny all! If you are unsure, do NOT add a permission!

https://dev.twitch.tv/docs/authentication#scopes

Functions

func Banner() string

func Exists

func Exists(path string) bool

Exists will check if a file exists

func GetenvInt

func GetenvInt(key string) int

func IsUser

func IsUser(i int) (bool, error)

func KillActiveStream

func KillActiveStream(x *ActiveStream) error

KillActiveStream will force kill an active stream.

func LocalhostServerGetParameters

func LocalhostServerGetParameters(d *CallbackText) (chan []byte, chan error)

LocalhostServerGetParameters will run an HTTP server on localhost and listen for parameters passed back over the GET request to populate the parameters into JSON returned over the []byte channel

func Open

func Open(args []string) error

func OpenInBrowserDefault

func OpenInBrowserDefault(url string) error

OpenInBrowserDefault will try to open a URL in one of the default browsers

func PrintBanner

func PrintBanner()

func S

func S(s string) *string

func SPointer

func SPointer(s string) *string

func SharedValues

func SharedValues(w http.ResponseWriter, r *http.Request)

SharedValues will plumb shared values back over the queue

func SharedValuesDynamic

func SharedValuesDynamic(d *CallbackText) func(w http.ResponseWriter, r *http.Request)

func StopActiveStream

func StopActiveStream(x *ActiveStream) error

StopActiveStream will stop an active stream.

func StrInt0

func StrInt0(n string) int

Types

type ActiveStream

type ActiveStream struct {
	Title       string
	Description string
	PID         int
	PID64       int64
	Client      activestreamer.ActiveStreamerClient
}

func GetActiveStream

func GetActiveStream() (*ActiveStream, error)

GetActiveStream will attempt to lookup an active stream running locally.

func NewActiveStream

func NewActiveStream(title, description string) (*ActiveStream, error)

NewActiveStream will create a new active stream as long as one does not exist.

func (*ActiveStream) Assure

func (x *ActiveStream) Assure() error

Assure will run a sanity check against the active stream to assure that it is running, healthy, and that we can talk to it.

func (*ActiveStream) InfoChannel

func (x *ActiveStream) InfoChannel() chan string

InfoChannel will return a channel that can be accessed to gain information about the stream.

type ActiveStreamerServer

type ActiveStreamerServer struct {
	activestreamer.UnimplementedActiveStreamerServer
	Local    *rtmp.URLAddr
	Remotes  map[string]*rtmp.URLAddr
	Listener *rtmp.Listener
	Server   *rtmp.Server
}

func NewActiveStreamerServer

func NewActiveStreamerServer() *ActiveStreamerServer

func (*ActiveStreamerServer) ProxyRTMP

func (*ActiveStreamerServer) StartRTMP

func (*ActiveStreamerServer) StopRTMP

func (*ActiveStreamerServer) Transact

type CallbackText

type CallbackText struct {
	Title       string
	MainHeading string
	SubHeading1 string
	SubHeading2 string
}

type ExecResult

type ExecResult struct {
	Command *exec.Cmd
	Stdout  *bytes.Buffer
	Stderr  *bytes.Buffer
}

ExecResult is the response from executing a command

func ExecCommand

func ExecCommand(cmd string, args []string) (*ExecResult, error)

ExecCommand is a wrapper for exec.Command but with a dedicated result{} struct. This works better for my brain.

type InteractiveTwitchClient

type InteractiveTwitchClient struct {
	AppID     string
	AppSecret string
	LoginURL  string
	Client    *helix.Client
}

func NewInteractiveTwitchClient

func NewInteractiveTwitchClient() *InteractiveTwitchClient

func (*InteractiveTwitchClient) Authenticate

func (c *InteractiveTwitchClient) Authenticate() error

type OBSClient

type OBSClient struct {
	Client *obsws.Client
}

func NewOBSClient

func NewOBSClient() *OBSClient

func (*OBSClient) Authenticate

func (c *OBSClient) Authenticate() error

type Stream

type Stream struct {
	Shutdown        chan bool
	IsManagedDaemon bool
	Server          *grpc.Server
}

func NewStream

func NewStream() *Stream

func (*Stream) Run

func (s *Stream) Run() error

Run will run the stream until a client tells it to stop.

func (*Stream) ServerGRPC

func (s *Stream) ServerGRPC() error

func (*Stream) SigHandler

func (s *Stream) SigHandler()

type Streamer

type Streamer struct {
	Title       string
	Description string

	TwitchClient  *InteractiveTwitchClient
	OBSClient     *OBSClient
	YouTubeClient *YouTubeClient
	// contains filtered or unexported fields
}

func NewStreamer

func NewStreamer(title, description string) *Streamer

func (*Streamer) SetDryRun

func (s *Streamer) SetDryRun(dryRun bool)

func (*Streamer) Start

func (s *Streamer) Start() error

type TwitchCallbackParameters

type TwitchCallbackParameters struct {
	Code  []string // The response code from authenticating with Twitch
	Scope []string // scope:scope+scope:scope
	Error []string // Sometimes we can receive errors - so lets at least log them
}

type YouTubeClient

type YouTubeClient struct {
	Client *youtube.Service
}

func NewYouTubeClient

func NewYouTubeClient() *YouTubeClient

func (*YouTubeClient) Authenticate

func (c *YouTubeClient) Authenticate() error

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL