Skip to content
This repository has been archived by the owner on Feb 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #36 from dbarbuzzi/bugfix/fix-auth-query
Browse files Browse the repository at this point in the history
  • Loading branch information
dbarbuzzi authored Jan 15, 2021
2 parents 6e5a30d + b6f7082 commit 9b49790
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 97 deletions.
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ tvd (**T**witch **V**OD **D**ownloader) is a command-line tool to download VODs

## Prerequisites

* If building from source, you must register a new app on the Twitch Dev site to get your own client ID
* If building from source, you must have a client ID with appropriate privileges to query the GQL API for VODs
* Provided releases have an embedded client ID
* You must have an active auth token from an account sign-in
* In a browser, sign into your account and get the value of the `auth-token` cookie

## Download

Expand Down Expand Up @@ -43,7 +41,6 @@ Using a config file is alternative to command-line arguments. It can be used in

The accepted values are:

* `AuthToken` - your login session’s auth token (stored in `auth-token` cookies)
* `ClientID` - your Twitch app’s client ID
* `Quality` (optional) - desired quality (e.g. “720p60”, “480p30”); can use “best” for best available (default: "best")
* `StartTime` – start time in the format "HOURS MINUTES SECONDS" (e.g. "1 24 35" is 1h24m35s)
Expand All @@ -59,7 +56,6 @@ The accepted values are:

All options supported above are also supported through the command-line under the following flags:

* `auth` => `AuthToken`
* `client` => `ClientID`
* `quality` => `Quality`
* `start` => `StartTime`
Expand Down
1 change: 0 additions & 1 deletion config-sample.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
AuthToken = "<access token from browser cookies>"
ClientID="<twitch api client id>"
Quality="best"
StartTime="0 0 0"
Expand Down
11 changes: 0 additions & 11 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

// Config represents a config object containing everything needed to download a VOD
type Config struct {
AuthToken string
ClientID string
Quality string
StartTime string
Expand All @@ -29,16 +28,12 @@ type Config struct {
// Privatize returns a copy of the struct with the ClientID field censored (e.g. for logging)
func (c Config) Privatize() Config {
c2 := c
c2.AuthToken = "********"
c2.ClientID = "********"
return c2
}

// Update replaces any config values in the base object with those present in the passed argument
func (c *Config) Update(c2 Config) {
if c2.AuthToken != "" {
c.AuthToken = c2.AuthToken
}
if c2.ClientID != "" {
c.ClientID = c2.ClientID
}
Expand Down Expand Up @@ -73,9 +68,6 @@ func (c *Config) Update(c2 Config) {
//
// Currently, "OutputFolder" is not validated (needs logic to support Windows paths)
func (c Config) Validate() error {
if len(c.AuthToken) == 0 {
return fmt.Errorf("error: AuthToken missing")
}
if len(c.ClientID) == 0 {
return fmt.Errorf("error: ClientID missing")
}
Expand Down Expand Up @@ -171,9 +163,6 @@ func loadConfig(f string) (Config, error) {
func buildConfigFromFlags() (Config, error) {
var config Config

if *authToken != "" {
config.AuthToken = *authToken
}
if *clientID != "" {
config.ClientID = *clientID
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/BurntSushi/toml v0.3.0
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
github.com/grafov/m3u8 v0.11.1
github.com/pkg/errors v0.8.0
github.com/schollz/progressbar/v3 v3.7.3
github.com/stretchr/testify v1.6.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/grafov/m3u8 v0.11.1 h1:igZ7EBIB2IAsPPazKwRKdbhxcoBKO3lO1UY57PZDeNA=
github.com/grafov/m3u8 v0.11.1/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
Expand Down
44 changes: 38 additions & 6 deletions structs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/json"
"log"
"net/url"
"path/filepath"
Expand Down Expand Up @@ -44,16 +45,47 @@ func isValidFilename(fn string) bool {
return true
}

// AuthTokenResponse represents the (happy) JSON response to a token request call
type AuthTokenResponse struct {
Sig string `json:"sig"`
Token string `json:"token"`
}

// Chunk represents a video chunk from the m3u
type Chunk struct {
Name string
Length float64
URL *url.URL
Path string
}

// AuthGQLPayload represents the payload sent to the GQL endpoint to get the
// auth token and signature
type AuthGQLPayload struct {
OperationName string `json:"operationName"`
Query string `json:"query"`
Variables struct {
IsLive bool `json:"isLive"`
IsVod bool `json:"isVod"`
Login string `json:"login"`
PlayerType string `json:"playerType"`
VodID string `json:"vodID"`
} `json:"variables"`
}

func generateAuthPayload(vodID string) ([]byte, error) {
ap := AuthGQLPayload{
OperationName: "PlaybackAccessToken_Template",
Query: "query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!) { streamPlaybackAccessToken(channelName: $login, params: {platform: \"web\", playerBackend: \"mediaplayer\", playerType: $playerType}) @include(if: $isLive) { value signature __typename } videoPlaybackAccessToken(id: $vodID, params: {platform: \"web\", playerBackend: \"mediaplayer\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",
}
ap.Variables.IsLive = false
ap.Variables.IsVod = true
ap.Variables.PlayerType = "site"
ap.Variables.VodID = vodID
return json.Marshal(ap)
}

// AuthGQLPayload represents the response from to the GQL endpoint containing
// the auth token and signature
type AuthGQLResponse struct {
Data struct {
VideoPlaybackAccessToken struct {
Value string `json:"value"`
Signature string `json:"signature"`
} `json:"videoPlaybackAccessToken"`
} `json:"data"`
}
Loading

0 comments on commit 9b49790

Please sign in to comment.