Skip to content

Commit

Permalink
Remove swfextract dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
juntaki committed Jul 20, 2017
1 parent cf42958 commit eecf406
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 91 deletions.
30 changes: 5 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,14 @@ fmt.Printf("%v", stations)

### ■ Get & Set authentication token

- swftools is required.

```go
// 1. Download a swf player.
swfPath := path.Join(dir, "myplayer.swf")
if err := radiko.DownloadPlayer(swfPath); err != nil {
log.Fatalf("Failed to download swf player. %s", err)
}

// 2. Using swfextract, create an authkey file from a swf player.
cmdPath, err := exec.LookPath("swfextract")
if err != nil {
log.Fatal(err)
}
authKeyPath := path.Join(dir, "authkey.png")
if c := exec.Command(cmdPath, "-b", "12", swfPath, "-o", authKeyPath); err != c.Run() {
log.Fatalf("Failed to execute swfextract. %s", err)
}

// 3. Create a new Client.
// 1. Create a new Client.
client, err := radiko.New("")
if err != nil {
panic(err)
}

// 4. Enables and sets the auth_token.
// 2. Enables and sets the auth_token.
// After client.AuthorizeToken() has succeeded,
// the client has the enabled auth_token internally.
authToken, err := client.AuthorizeToken(context.Background(), authKeyPath)
Expand All @@ -72,16 +54,14 @@ if err != nil {

#### Premium member (Enable to use the [area free](http://radiko.jp/rg/premium/).)

Step 1,2 are the same as above.

```go
// 3. Create a new Client.
// 1. Create a new Client.
client, err := radiko.New("")
if err != nil {
panic(err)
}

// 4. Login as the premium member
// 2. Login as the premium member
// After client.Login() has succeeded,
// the client has the valid cookie internally.
ctx := context.Background()
Expand All @@ -94,7 +74,7 @@ if login.StatusCode() != 200 {
login.StatusCode())
}

// 5. Enables and sets the auth_token.
// 3. Enables and sets the auth_token.
// After client.AuthorizeToken() has succeeded,
// the client has the enabled auth_token internally.
authToken, err := client.AuthorizeToken(context.Background(), authKeyPath)
Expand Down
14 changes: 9 additions & 5 deletions auth.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
package radiko

import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
)

// AuthorizeToken returns an enables auth_token and error,
// and sets auth_token in Client.
// Is is a alias function that wraps Auth1Fms and Auth2Fms.
func (c *Client) AuthorizeToken(ctx context.Context, pngFile string) (string, error) {
authToken, length, offset, err := c.Auth1Fms(ctx)
func (c *Client) AuthorizeToken(ctx context.Context) (string, error) {
bin, err := downloadBinary()
if err != nil {
return "", err
}

f, err := os.Open(pngFile)
f := bytes.NewReader(bin)

authToken, length, offset, err := c.Auth1Fms(ctx)
if err != nil {
return "", err
}

b := make([]byte, length)
if _, err = f.ReadAt(b, offset); err != nil {
io.CopyN(ioutil.Discard, f, offset)
if _, err = f.Read(b); err != nil {
return "", err
}
partialKey := base64.StdEncoding.EncodeToString(b)
Expand Down
17 changes: 1 addition & 16 deletions auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ func TestAuthorizeToken(t *testing.T) {
}

ctx := context.Background()
pngPath := path.Join(testdataDir, "authkey.png")
authToken, err := c.AuthorizeToken(ctx, pngPath)
authToken, err := c.AuthorizeToken(ctx)
if err != nil {
t.Error(err)
}
Expand All @@ -29,20 +28,6 @@ func TestAuthorizeToken(t *testing.T) {
}
}

func TestAuthorizeToken_NotExistAuthkeyFile(t *testing.T) {
c, err := New("")
if err != nil {
t.Fatalf("Failed to construct client: %s", err)
}

ctx := context.Background()
pngFile := path.Join(testdataDir, "not_exist_authkey.png")
_, err = c.AuthorizeToken(ctx, pngFile)
if err == nil {
t.Error(err)
}
}

func TestAuth1Fms(t *testing.T) {
c, err := New("")
if err != nil {
Expand Down
27 changes: 3 additions & 24 deletions examples/auth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,21 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path"

radiko "github.com/yyoshiki41/go-radiko"
)

func main() {
dir, f := createTempDir()
defer f()

// 1. Download a swf player
swfPath := path.Join(dir, "myplayer.swf")
if err := radiko.DownloadPlayer(swfPath); err != nil {
log.Fatalf("Failed to download swf player. %s", err)
}

// 2. Using swfextract, create an authkey file from a swf player.
cmdPath, err := exec.LookPath("swfextract")
if err != nil {
log.Fatal(err)
}
authKeyPath := path.Join(dir, "authkey.png")
if c := exec.Command(cmdPath, "-b", "12", swfPath, "-o", authKeyPath); err != c.Run() {
log.Fatalf("Failed to execute swfextract. %s", err)
}

// 3. Create a new Client.
// 1. Create a new Client.
client, err := radiko.New("")
if err != nil {
log.Fatalf("Failed to construct a radiko Client. %s", err)
}

// 4. Enables and sets the auth_token.
// 2. Enables and sets the auth_token.
// After client.AuthorizeToken() has succeeded,
// the client has the enabled auth_token internally.
authToken, err := client.AuthorizeToken(context.Background(), authKeyPath)
authToken, err := client.AuthorizeToken(context.Background())
if err != nil {
log.Fatal(err)
}
Expand Down
81 changes: 71 additions & 10 deletions player.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,92 @@
package radiko

import (
"compress/zlib"
"errors"
"io"
"io/ioutil"
"net/http"
"os"
)

const (
playerURL = "http://radiko.jp/apps/js/flash/myplayer-release.swf"
)

// DownloadPlayer downloads a swf player file.
func DownloadPlayer(path string) error {
func downloadBinary() ([]byte, error) {
resp, err := http.Get(playerURL)
if err != nil {
return err
return nil, err
}
defer resp.Body.Close()

f, err := os.Create(path)
return swfExtract(resp.Body)
}

const targetID = 12 // swfextract -b "12"
const targetCode = 87 // swfextract "-b" 12

const headerCWS = 8
const headerRect = 5
const rectNum = 4
const headerRest = 2 + 2
const binaryOffset = 6

func swfExtract(body io.Reader) ([]byte, error) {
io.CopyN(ioutil.Discard, body, headerCWS)
zf, err := zlib.NewReader(body)
if err != nil {
return err
return nil, err
}
buf, err := ioutil.ReadAll(zf)
if err != nil {
return nil, err
}

offset := 0

// Skip Rect
rectSize := int(buf[offset] >> 3)
rectOffset := (headerRect + rectNum*rectSize + 7) / 8

offset += rectOffset

// Skip the rest header
offset += headerRest

// Read tags
for i := 0; ; i++ {
// tag code
code := int(buf[offset+1])<<2 + int(buf[offset])>>6

// tag length
len := int(buf[offset] & 0x3f)

// Skip tag header
offset += 2

// tag length (if long version)
if len == 0x3f {
len = int(buf[offset])
len += int(buf[offset+1]) << 8
len += int(buf[offset+2]) << 16
len += int(buf[offset+3]) << 24

// skip tag lentgh header
offset += 4
}

// Not found...
if code == 0 {
return nil, errors.New("swf extract failed")
}
// tag ID
id := int(buf[offset]) + int(buf[offset+1])<<8

// Found?
if code == targetCode && id == targetID {
return buf[offset+binaryOffset : offset+len], nil
}

_, err = io.Copy(f, resp.Body)
if closeErr := f.Close(); err == nil {
err = closeErr
offset += len
}
return err
}
15 changes: 4 additions & 11 deletions player_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
package radiko

import (
"path"
"testing"
)
import "testing"

func TestDownloadPlayer(t *testing.T) {
dir, removeDir := createTestTempDir(t)
defer removeDir() // clean up

playerPath := path.Join(dir, "myplayer.swf")
err := DownloadPlayer(playerPath)
func TestDownloadBinary(t *testing.T) {
_, err := downloadBinary()
if err != nil {
t.Errorf("Failed to download player.swf: %s", err)
t.Errorf("Failed to download binary: %s", err)
}
}

0 comments on commit eecf406

Please sign in to comment.