Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

few extra features #16

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open

few extra features #16

wants to merge 41 commits into from

Conversation

akhoury
Copy link

@akhoury akhoury commented Feb 25, 2016

List of additions/changes (all backward compatible)

parser

  • added an options parameter to createStream(options)
    • options.lax a true/false boolean which basically forgives the parsed text if it doesn't start by an EXTM3U tag, this is useful for merging many m3u8s into one, while tailing a large Live file.
    • options.beforeItemEmit() a function hook which gets called before the emit of each item event, passing the currentItem as the 1st argument. The reason this was useful in my use case is because I had m3u8s without the program-date-time tag, where the .ts files were named using timestamps, so before each item emit, I was doing something like this currentItem.set('date', new Date(currentItem.get('uri'))); - who knew that ffmpeg does not support the inclusion of EXT-X-PROGRAM-DATE-TIME on each segment while generating m3u8s from a raw stream.
  • added parser['EXT-X-PROGRAM-DATE-TIME'](), since m3u.toString() does output it if available but the current parser ignores it.

m3u

  • added m3u.clone() basically just returns a clone of the m3u object.
  • added m3u.concat() which behaves exactly like how m3u.merge() behaves but it returns a new m3u object, basically just concats the playlist items.
  • added m3u.mergeByUri() to do a real unique merge, using each item.uri as the identifier, returns a new m3u object
  • added m3u.mergeByDate() to do a real unique merge using each item.date to find the stream gaps of stream-A and fill them in with slices of stream-B, returns a new m3u object
  • added some slicing functions, which each returns a new m3u object with a slice of the PlaylistItems. Also, slicing a live m3u while using an end-range, will make the returned m3u as VOD, since the slice has an ending.
    • m3u.sliceByIndex(), (alias m3u.slice()) slices based on the segments indices, returns a new m3u object
    • m3u.sliceBySeconds(), slices based on the position of each segment on the timeline of video seconds duration, returns a new m3u object
    • m3u.sliceByDates() slices based on the position of each segment on the timeline of real time (depends on the EXT-X-PROGRAM-DATE-TIME tag of course, or a custom item.date being set via the beforeItemEmit hook), returns a new m3u object
  • added m3u.insertPlaylistItemsAfter([newItems], afterItem)
  • added m3u.findDateGaps() used by m3u.mergeByDate()
  • added m3u.sortByDate(), sorting is useful if you're merging un-ordered or random playlists
  • added m3u.sortByUri()
  • added m3u.resetTargetDuration() which would either take a newTargetDuration to compare it and set it, or a true boolean to re-check all the PlaylistItems and figure out the max duration to use.
  • added m3u.isDateSupported()
  • added 2 functions to keep track if an ENDLIST tag was actually found, then it's a VOD since EXT-X-PLAYLIST-TYPE is optional and might not be there.
    • m3u.isVOD()
    • m3u.isLive()
  • added m3u.isMaster() if it's a master playlist or not.

Notes

  • I think m3u.merge() should return a clone instead of mutating self, but that would be breaking change - OR if you prefer mutating self all the time, we can change all the other merging and slicing functions, i.e. m3u.slice*(), to mutate self as well instead of returning a clone, let me know what you think - I was just trying to mimic what the javascript Array does when doing an array.slice() or array.concat(), both of these 2 return a new array.

Tests

I think I covered all the things I added :), still a little shy but I will submit more as I move along.

@bog bog self-assigned this Mar 22, 2016
@bog
Copy link
Contributor

bog commented Mar 22, 2016

Wow, thanks for this. I'll be taking a closer look soon.

```
{
	"message": "createM3U is not defined",
	"stack": "ReferenceError: createM3U is not defined\n    at M3U.mergeByDate (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/m3u8/m3u.js:190:80)\n    at /Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/lib/index.js:295:24\n    at tryCatchResolve (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/apply.js:46:23)\n    at callAndResolve (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/apply.js:30:12)\n    at callAndResolveNext (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/apply.js:40:4)\n    at tryCatchReject3 (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/makePromise.js:856:7)\n    at runContinuation3 (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/makePromise.js:814:4)\n    at Fulfilled.fold (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/makePromise.js:588:4)\n    at callAndResolve (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/apply.js:34:12)\n    at callAndResolveNext (/Users/akhoury/Perforce/akhoury_azizs-mac-mini_4287/speech/ramp/sites/m3u8-service/node_modules/when/lib/apply.js:40:4)"
}
```
@blainsmith
Copy link

Wow, these are awesome additions! I'd love to take advantage of all of these. If you need help reviewing to get this PR merged I would be glad to. I have this module used in production now and I'd love these new additions/fixes.

@bog
Copy link
Contributor

bog commented May 17, 2016

I haven't had time yet. If you have time @blainsmith, it'd be appreciated.

@blainsmith
Copy link

Great, I will poke around at it. If you ever need another maintainer I'd be glad to help out. I do rely on this plugin a lot so I would love it to stay alive. We are using it at http://oddnetworks.com

@blainsmith
Copy link

So I found and issue with isLive() and isVOD() and that is with the following:

#EXTM3U

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-1",NAME="Audio",LANGUAGE="en",AUTOSELECT=YES,URI="audio_0_128000_hls.m3u8"

#EXT-X-STREAM-INF:BANDWIDTH=4928000,CODECS="avc1.64000d,mp4a.40.2",RESOLUTION=1280x544,AUDIO="audio-1"
video_0_2400000_hls.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2528000,CODECS="avc1.64000d,mp4a.40.2",RESOLUTION=854x362,AUDIO="audio-1"
video_0_1200000_hls.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1728000,CODECS="avc1.64000d,mp4a.40.2",RESOLUTION=640x272,AUDIO="audio-1"
video_0_800000_hls.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=928000,CODECS="avc1.64000d,mp4a.40.2",RESOLUTION=426x180,AUDIO="audio-1"
video_0_400000_hls.m3u8

This is actually a VOD, but it is the master.m3u8 file defining the bitrates. Unfortunately, you cannot tell it is either live or VOD until you parse the subsequent m3u8 urls (video_0_X_hls.m3u8). In most cases EXT-X-PLAYLIST-TYPE and EXT-X-ENDLIST will never appear in a file like this. Perhaps an isMaster() method to account for this 3rd format would help identify them.

@akhoury
Copy link
Author

akhoury commented May 18, 2016

Sounds good, I can add that in

@akhoury
Copy link
Author

akhoury commented Jun 28, 2016

@bog, @blainsmith any more comments? and/or any idea when this would be merged? if accepted

@tjenkinson
Copy link

I could do with these new features as well :)

@tjenkinson
Copy link

I'm working on a fork for now so I have can point to it from a package.json file. Will switch it to point here when this is merged :)

@akhoury
Copy link
Author

akhoury commented Dec 22, 2016

ping @bog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants