Skip to content

Commit

Permalink
Upstream merge (zencoder#3)
Browse files Browse the repository at this point in the history
* support custom tag decode/encode

* add unit tests

* go fmt

* add go.mod

* add writer tests, breakup custom interface

* update readme

* add comments to exports

* parse custom tags first

* update CustomDecoder.Segment to CustomDecoder.SegmentTag

* Add badge of godoc.org for the awesome-go

* Fix formatting with gofmt

Also copyrights updated.

Refs to issue grafov#151.

* Fix comments by golint recommendations

Refs to issue grafov#151.

* Simplify with gofmt

Refs to issue grafov#151.

* Fix comments accordingly with golint advices

Refs to issue grafov#151.

* Integrate with deepsource.io

It bring us more code quality analyzers.
Refs grafov#151.

* Add deepsource.io badge

Refs grafov#151.

* Add awesome-go badge

Refs to issue grafov#151.

* Try vanity import to work w/ travis

* remove coveralls from fork

Co-authored-by: Matthew Neil <[email protected]>
Co-authored-by: Lei Gao <[email protected]>
Co-authored-by: Alexander I.Grafov <[email protected]>
  • Loading branch information
4 people authored Oct 7, 2020
1 parent 08b2d91 commit 6485cdb
Show file tree
Hide file tree
Showing 17 changed files with 935 additions and 172 deletions.
16 changes: 16 additions & 0 deletions .deepsource.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version = 1

test_patterns = [
"*_test.go"
]

exclude_patterns = [
"vendor/**"
]

[[analyzers]]
name = "go"
enabled = true

[analyzers.meta]
import_path = "github.com/grafov/m3u8"
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
language: go
go_import_path: github.com/grafov/m3u8

# Versions of go that are explicitly supported.
go:
Expand All @@ -10,10 +11,8 @@ go:
# Required for coverage.
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls

script:
- go build -a -v ./...
- diff <(gofmt -d .) <("")
- go test -v -covermode=count -coverprofile=coverage.out
- $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis-ci
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ to the project. They listed below in an alphabetical order:
- Vishal Kumar Tuniki <[email protected]>
- Yevgen Flerko <[email protected]>
- Zac Shenker <[email protected]>

- Matthew Neil [mjneil](https://github.com/mjneil)

If you want to be added to this list (or removed for any reason)
just open an issue about it.
37 changes: 22 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--*- mode:markdown -*-->
M3U8
M3U8 [![](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#video)
====

This is the most complete opensource library for parsing and generating of M3U8 playlists
Expand All @@ -15,7 +15,7 @@ ways to play HLS or handle playlists over HTTP. So library features are:
* Encryption keys support for use with DRM systems like [Verimatrix](http://verimatrix.com) etc.
* Support for non standard [Google Widevine](http://www.widevine.com) tags.

The library covered by BSD 3-clause license. See [LICENSE](LICENSE) for the full text.
The library covered by BSD 3-clause license. See [LICENSE](LICENSE) for the full text.
Versions 0.8 and below was covered by GPL v3. License was changed from the version 0.9 and upper.

See the list of the library authors at [AUTHORS](AUTHORS) file.
Expand All @@ -27,7 +27,7 @@ Install

or get releases from https://github.com/grafov/m3u8/releases

Documentation [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/grafov/m3u8)
Documentation [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/grafov/m3u8) [![GoDoc](https://godoc.org/github.com/grafov/m3u8?status.svg)](https://godoc.org/github.com/grafov/m3u8)
-------------

Package online documentation (examples included) available at:
Expand Down Expand Up @@ -81,6 +81,11 @@ You may use API methods to fill structures or create them manually to generate p
fmt.Println(p.Encode().String())
```

Custom Tags
-----------

M3U8 supports parsing and writing of custom tags. You must implement both the `CustomTag` and `CustomDecoder` interface for each custom tag that may be encountered in the playlist. Look at the template files in `example/template/` for examples on parsing custom playlist and segment tags.

Library structure
-----------------

Expand Down Expand Up @@ -111,33 +116,35 @@ Also the library used in opensource software so you may look at these apps for u
* [HLS utils](https://github.com/archsh/hls-utils)
* [M3U8 reader](https://github.com/jeongmin/m3u8-reader)

M3U8 parsing/generation in other languages
------------------------------------------

* https://github.com/globocom/m3u8 in Python
* https://github.com/zencoder/m3uzi in Ruby
* https://github.com/Jeanvf/M3U8Paser in Objective C
* https://github.com/tedconf/node-m3u8 in Javascript
* http://sourceforge.net/projects/m3u8parser/ in Java
* https://github.com/karlll/erlm3u8 in Erlang

Project status [![Go Report Card](https://goreportcard.com/badge/grafov/m3u8)](https://goreportcard.com/report/grafov/m3u8)
--------------

[![Build Status](https://travis-ci.org/grafov/m3u8.png?branch=master)](https://travis-ci.org/grafov/m3u8) [![Build Status](https://cloud.drone.io/api/badges/grafov/m3u8/status.svg)](https://cloud.drone.io/grafov/m3u8) [![Coverage Status](https://coveralls.io/repos/github/grafov/m3u8/badge.svg?branch=master)](https://coveralls.io/github/grafov/m3u8?branch=master)

[![DeepSource](https://static.deepsource.io/deepsource-badge-light.svg)](https://deepsource.io/gh/grafov/m3u8/?ref=repository-badge)

Code coverage: https://gocover.io/github.com/grafov/m3u8

Project maintainers:

* Lei Gao @leikao
* Bradley Falzon @bradleyfalzon
* Alexander Grafov @grafov

State of code coverage: https://gocover.io/github.com/grafov/m3u8

Roadmap
-------

To version 1.0:

* Support all M3U8 tags up to latest version of specs.
* Code coverage by unit tests up to 90%

FYI M3U8 parsing/generation in other languages
------------------------------------------

* https://github.com/globocom/m3u8 in Python
* https://github.com/zencoder/m3uzi in Ruby
* https://github.com/Jeanvf/M3U8Paser in Objective C
* https://github.com/tedconf/node-m3u8 in Javascript
* http://sourceforge.net/projects/m3u8parser/ in Java
* https://github.com/karlll/erlm3u8 in Erlang
68 changes: 38 additions & 30 deletions doc.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
/* Package M3U8 is parser & generator library for Apple HLS.
// Package m3u8 is parser & generator library for Apple HLS.

This is a most complete opensource library for parsing and generating of M3U8 playlists used in HTTP Live Streaming (Apple HLS) for internet video translations.
/* This is a most complete opensource library for parsing and
generating of M3U8 playlists used in HTTP Live Streaming (Apple
HLS) for internet video translations.
M3U8 is simple text format and parsing library for it must be simple too. It did not offer ways to play HLS or handle playlists over HTTP. Library features are:
M3U8 is simple text format and parsing library for it must be simple
too. It did not offer ways to play HLS or handle playlists over
HTTP. Library features are:
* Support HLS specs up to version 5 of the protocol.
* Parsing and generation of master-playlists and media-playlists.
Expand All @@ -11,46 +15,50 @@ M3U8 is simple text format and parsing library for it must be simple too. It did
* Encryption keys support for usage with DRM systems like Verimatrix (http://verimatrix.com) etc.
* Support for non standard Google Widevine (http://www.widevine.com) tags.
Library coded accordingly with IETF draft http://tools.ietf.org/html/draft-pantos-http-live-streaming
Library coded accordingly with IETF draft
http://tools.ietf.org/html/draft-pantos-http-live-streaming
Examples of usage may be found in *_test.go files of a package. Also see below some simple examples.
Examples of usage may be found in *_test.go files of a package. Also
see below some simple examples.
Create simple media playlist with sliding window of 3 segments and maximum of 50 segments.
Create simple media playlist with sliding window of 3 segments and
maximum of 50 segments.
p, e := NewMediaPlaylist(3, 50)
if e != nil {
panic(fmt.Sprintf("Create media playlist failed: %s", e))
}
for i := 0; i < 5; i++ {
e = p.Add(fmt.Sprintf("test%d.ts", i), 5.0)
if e != nil {
panic(fmt.Sprintf("Add segment #%d to a media playlist failed: %s", i, e))
}
}
fmt.Println(p.Encode(true).String())
p, e := NewMediaPlaylist(3, 50)
if e != nil {
panic(fmt.Sprintf("Create media playlist failed: %s", e))
}
for i := 0; i < 5; i++ {
e = p.Add(fmt.Sprintf("test%d.ts", i), 5.0)
if e != nil {
panic(fmt.Sprintf("Add segment #%d to a media playlist failed: %s", i, e))
}
}
fmt.Println(p.Encode(true).String())
We add 5 testX.ts segments to playlist then encode it to M3U8 format and convert to string.
We add 5 testX.ts segments to playlist then encode it to M3U8 format
and convert to string.
Next example shows parsing of master playlist:
f, err := os.Open("sample-playlists/master.m3u8")
if err != nil {
fmt.Println(err)
}
p := NewMasterPlaylist()
err = p.DecodeFrom(bufio.NewReader(f), false)
if err != nil {
fmt.Println(err)
}
f, err := os.Open("sample-playlists/master.m3u8")
if err != nil {
fmt.Println(err)
}
p := NewMasterPlaylist()
err = p.DecodeFrom(bufio.NewReader(f), false)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Playlist object: %+v\n", p)
fmt.Printf("Playlist object: %+v\n", p)
We are open playlist from the file and parse it as master playlist.
*/

package m3u8

// Copyright 2013-2017 The Project Developers.
// Copyright 2013-2019 The Project Developers.
// See the AUTHORS and LICENSE files at the top-level directory of this distribution
// and at https://github.com/grafov/m3u8/

Expand Down
12 changes: 10 additions & 2 deletions example/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,27 @@ import (
"path"

"github.com/grafov/m3u8"
"github.com/grafov/m3u8/example/template"
)

func main() {
GOPATH := os.Getenv("GOPATH")
if GOPATH == "" {
panic("$GOPATH is empty")
}
m3u8File := "github.com/grafov/m3u8/sample-playlists/media-playlist-with-byterange.m3u8"

m3u8File := "github.com/grafov/m3u8/sample-playlists/media-playlist-with-custom-tags.m3u8"
f, err := os.Open(path.Join(GOPATH, "src", m3u8File))
if err != nil {
panic(err)
}
p, listType, err := m3u8.DecodeFrom(bufio.NewReader(f), true)

customTags := []m3u8.CustomDecoder{
&template.CustomPlaylistTag{},
&template.CustomSegmentTag{},
}

p, listType, err := m3u8.DecodeWith(bufio.NewReader(f), true, customTags)
if err != nil {
panic(err)
}
Expand Down
52 changes: 52 additions & 0 deletions example/template/custom-playlist-tag-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package template

import (
"bytes"
"fmt"
"strconv"

"github.com/grafov/m3u8"
)

// #CUSTOM-PLAYLIST-TAG:<number>

// CustomPlaylistTag implements both CustomTag and CustomDecoder
// interfaces.
type CustomPlaylistTag struct {
Number int
}

// TagName should return the full indentifier including the leading
// '#' and trailing ':' if the tag also contains a value or attribute
// list.
func (tag *CustomPlaylistTag) TagName() string {
return "#CUSTOM-PLAYLIST-TAG:"
}

// Decode decodes the input line. The line will be the entire matched
// line, including the identifier
func (tag *CustomPlaylistTag) Decode(line string) (m3u8.CustomTag, error) {
_, err := fmt.Sscanf(line, "#CUSTOM-PLAYLIST-TAG:%d", &tag.Number)

return tag, err
}

// SegmentTag is a playlist tag example.
func (tag *CustomPlaylistTag) SegmentTag() bool {
return false
}

// Encode formats the structure to the text result.
func (tag *CustomPlaylistTag) Encode() *bytes.Buffer {
buf := new(bytes.Buffer)

buf.WriteString(tag.TagName())
buf.WriteString(strconv.Itoa(tag.Number))

return buf
}

// String implements Stringer interface.
func (tag *CustomPlaylistTag) String() string {
return tag.Encode().String()
}
79 changes: 79 additions & 0 deletions example/template/custom-segment-tag-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package template

import (
"bytes"
"errors"

"github.com/grafov/m3u8"
)

// #CUSTOM-SEGMENT-TAG:<attribute-list>

// CustomSegmentTag implements both CustomTag and CustomDecoder
// interfaces.
type CustomSegmentTag struct {
Name string
Jedi bool
}

// TagName should return the full indentifier including the leading '#' and trailing ':'
// if the tag also contains a value or attribute list
func (tag *CustomSegmentTag) TagName() string {
return "#CUSTOM-SEGMENT-TAG:"
}

// Decode decodes the input string to the internal structure. The line
// will be the entire matched line, including the identifier.
func (tag *CustomSegmentTag) Decode(line string) (m3u8.CustomTag, error) {
var err error

// Since this is a Segment tag, we want to create a new tag every time it is decoded
// as there can be one for each segment with
newTag := new(CustomSegmentTag)

for k, v := range m3u8.DecodeAttributeList(line[20:]) {
switch k {
case "NAME":
newTag.Name = v
case "JEDI":
if v == "YES" {
newTag.Jedi = true
} else if v == "NO" {
newTag.Jedi = false
} else {
err = errors.New("Valid strings for JEDI attribute are YES and NO.")
}
}
}

return newTag, err
}

// SegmentTag is a playlist tag example.
func (tag *CustomSegmentTag) SegmentTag() bool {
return true
}

// Encode encodes the structure to the text result.
func (tag *CustomSegmentTag) Encode() *bytes.Buffer {
buf := new(bytes.Buffer)

if tag.Name != "" {
buf.WriteString(tag.TagName())
buf.WriteString("NAME=\"")
buf.WriteString(tag.Name)
buf.WriteString("\",JEDI=")
if tag.Jedi {
buf.WriteString("YES")
} else {
buf.WriteString("NO")
}
}

return buf
}

// String implements Stringer interface.
func (tag *CustomSegmentTag) String() string {
return tag.Encode().String()
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/grafov/m3u8

go 1.12
Loading

0 comments on commit 6485cdb

Please sign in to comment.