m3u8 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/m3u8/attribute_formatter.rb +17 -0
- data/lib/m3u8/date_range_item.rb +5 -5
- data/lib/m3u8/part_item.rb +1 -1
- data/lib/m3u8/segment_item.rb +2 -1
- data/lib/m3u8/version.rb +1 -1
- data/m3u8.gemspec +1 -0
- data/spec/lib/m3u8/date_range_item_spec.rb +20 -0
- data/spec/lib/m3u8/part_item_spec.rb +7 -0
- data/spec/lib/m3u8/segment_item_spec.rb +11 -0
- metadata +17 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 00157be29743342bb6156539b9fca6a1e67ae9ae60e74cab04eebeda10a888ec
|
|
4
|
+
data.tar.gz: f82b069b8fef0ce72694b11640431b25ea04caa7616ee69ab6c56e9f9029fdc3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 659a5a703d0a00887b9dc724bb252aeb56fb44010756772f8667b62ebd77b34b6b3a4f647c0c6aaf46cdfbfafbdf5173b59db2f1a84efa34fd4c5b4aafbab732
|
|
7
|
+
data.tar.gz: 07a539694c4231895fd0f7eebfb18f860c0dbbcbdd0f63e31b50ce7485937dc84fcac198ad443f9f6591bed7c17d32839bae7aba3904e452781e98520f21153c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'bigdecimal'
|
|
4
|
+
|
|
3
5
|
module M3u8
|
|
4
6
|
# Shared helpers for formatting HLS tag attributes
|
|
5
7
|
module AttributeFormatter
|
|
@@ -26,5 +28,20 @@ module M3u8
|
|
|
26
28
|
def boolean_format(key, value)
|
|
27
29
|
"#{key}=#{value == true ? 'YES' : 'NO'}" unless value.nil?
|
|
28
30
|
end
|
|
31
|
+
|
|
32
|
+
# Format a decimal attribute, ensuring it formatted as a floating-point
|
|
33
|
+
# number or integer
|
|
34
|
+
# @param number [Float, Integer, nil] the number to format
|
|
35
|
+
# @return [String, nil] formatted string or nil when value is nil
|
|
36
|
+
def decimal_format(number)
|
|
37
|
+
case number
|
|
38
|
+
when nil
|
|
39
|
+
nil
|
|
40
|
+
when Float
|
|
41
|
+
BigDecimal(number).to_s('F')
|
|
42
|
+
else
|
|
43
|
+
number.to_s
|
|
44
|
+
end
|
|
45
|
+
end
|
|
29
46
|
end
|
|
30
47
|
end
|
data/lib/m3u8/date_range_item.rb
CHANGED
|
@@ -131,8 +131,8 @@ module M3u8
|
|
|
131
131
|
quoted_format('CLASS', class_name),
|
|
132
132
|
%(START-DATE="#{start_date}"),
|
|
133
133
|
quoted_format('END-DATE', end_date),
|
|
134
|
-
unquoted_format('DURATION', duration),
|
|
135
|
-
unquoted_format('PLANNED-DURATION', planned_duration),
|
|
134
|
+
unquoted_format('DURATION', decimal_format(duration)),
|
|
135
|
+
unquoted_format('PLANNED-DURATION', decimal_format(planned_duration)),
|
|
136
136
|
client_attributes_format,
|
|
137
137
|
interstitial_formats,
|
|
138
138
|
unquoted_format('SCTE35-CMD', scte35_cmd),
|
|
@@ -147,7 +147,7 @@ module M3u8
|
|
|
147
147
|
|
|
148
148
|
client_attributes.map do |attribute|
|
|
149
149
|
value = attribute.last
|
|
150
|
-
fmt = decimal?(value) ? value : %("#{value}")
|
|
150
|
+
fmt = decimal?(value) ? decimal_format(value) : %("#{value}")
|
|
151
151
|
"#{attribute.first}=#{fmt}"
|
|
152
152
|
end
|
|
153
153
|
end
|
|
@@ -166,8 +166,8 @@ module M3u8
|
|
|
166
166
|
def interstitial_formats
|
|
167
167
|
[quoted_format('X-ASSET-URI', asset_uri),
|
|
168
168
|
quoted_format('X-ASSET-LIST', asset_list),
|
|
169
|
-
unquoted_format('X-RESUME-OFFSET', resume_offset),
|
|
170
|
-
unquoted_format('X-PLAYOUT-LIMIT', playout_limit),
|
|
169
|
+
unquoted_format('X-RESUME-OFFSET', decimal_format(resume_offset)),
|
|
170
|
+
unquoted_format('X-PLAYOUT-LIMIT', decimal_format(playout_limit)),
|
|
171
171
|
quoted_format('X-RESTRICT', restrict),
|
|
172
172
|
quoted_format('X-SNAP', snap),
|
|
173
173
|
quoted_format('X-TIMELINE-OCCUPIES', timeline_occupies),
|
data/lib/m3u8/part_item.rb
CHANGED
data/lib/m3u8/segment_item.rb
CHANGED
|
@@ -5,6 +5,7 @@ module M3u8
|
|
|
5
5
|
# optionally allowing an EXT-X-BYTERANGE tag to be set.
|
|
6
6
|
class SegmentItem
|
|
7
7
|
include M3u8
|
|
8
|
+
include AttributeFormatter
|
|
8
9
|
|
|
9
10
|
# @return [Float, nil] segment duration in seconds
|
|
10
11
|
# @return [String, nil] segment URI
|
|
@@ -32,7 +33,7 @@ module M3u8
|
|
|
32
33
|
# Render as an m3u8 EXTINF tag with segment URI.
|
|
33
34
|
# @return [String]
|
|
34
35
|
def to_s
|
|
35
|
-
"#EXTINF:#{duration},#{comment}#{byterange_format}" \
|
|
36
|
+
"#EXTINF:#{decimal_format(duration)},#{comment}#{byterange_format}" \
|
|
36
37
|
"\n#{date_format}#{segment}"
|
|
37
38
|
end
|
|
38
39
|
|
data/lib/m3u8/version.rb
CHANGED
data/m3u8.gemspec
CHANGED
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.files = `git ls-files -z`.split("\x0")
|
|
23
23
|
.grep_v(/\A(CLAUDE|AGENTS)\.md\z/)
|
|
24
24
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
25
|
+
spec.add_dependency 'bigdecimal'
|
|
25
26
|
spec.require_paths = ['lib']
|
|
26
27
|
|
|
27
28
|
end
|
|
@@ -172,6 +172,26 @@ describe M3u8::DateRangeItem do
|
|
|
172
172
|
expect(item.to_s).to eq(expected)
|
|
173
173
|
end
|
|
174
174
|
|
|
175
|
+
it 'should render small float values as floating-point number instead of scientific notation' do
|
|
176
|
+
options = { id: 'test_id', start_date: '2014-03-05T11:15:00Z',
|
|
177
|
+
duration: 0.00001,
|
|
178
|
+
planned_duration: 0.00002,
|
|
179
|
+
resume_offset: 0.00003,
|
|
180
|
+
playout_limit: 0.00004,
|
|
181
|
+
client_attributes: { 'X-CUSTOM' => 0.00005 } }
|
|
182
|
+
item = described_class.new(options)
|
|
183
|
+
|
|
184
|
+
expected = '#EXT-X-DATERANGE:ID="test_id",' \
|
|
185
|
+
'START-DATE="2014-03-05T11:15:00Z",' \
|
|
186
|
+
'DURATION=0.00001,' \
|
|
187
|
+
'PLANNED-DURATION=0.00002,' \
|
|
188
|
+
'X-CUSTOM=0.00005,' \
|
|
189
|
+
'X-RESUME-OFFSET=0.00003,' \
|
|
190
|
+
'X-PLAYOUT-LIMIT=0.00004'
|
|
191
|
+
|
|
192
|
+
expect(item.to_s).to eq(expected)
|
|
193
|
+
end
|
|
194
|
+
|
|
175
195
|
it 'should ignore optional attributes' do
|
|
176
196
|
options = { id: 'test_id', start_date: '2014-03-05T11:15:00Z' }
|
|
177
197
|
item = described_class.new(options)
|
|
@@ -56,5 +56,12 @@ describe M3u8::PartItem do
|
|
|
56
56
|
expected = '#EXT-X-PART:DURATION=1.5,URI="part1.ts"'
|
|
57
57
|
expect(item.to_s).to eq(expected)
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
it 'should render small float values as floating-point number instead of scientific notation' do
|
|
61
|
+
options = { duration: 0.00001, uri: 'part1.ts' }
|
|
62
|
+
item = described_class.new(options)
|
|
63
|
+
expected = '#EXT-X-PART:DURATION=0.00001,URI="part1.ts"'
|
|
64
|
+
expect(item.to_s).to eq(expected)
|
|
65
|
+
end
|
|
59
66
|
end
|
|
60
67
|
end
|
|
@@ -89,4 +89,15 @@ describe M3u8::SegmentItem do
|
|
|
89
89
|
'segment.aac'
|
|
90
90
|
expect(output).to eq expected
|
|
91
91
|
end
|
|
92
|
+
|
|
93
|
+
it 'converts very small durations to floating point' do
|
|
94
|
+
time = Time.iso8601('2020-11-25T20:27:00Z')
|
|
95
|
+
hash = { duration: 0.000001, segment: 'test.ts', program_date_time: time }
|
|
96
|
+
item = M3u8::SegmentItem.new(hash)
|
|
97
|
+
output = item.to_s
|
|
98
|
+
expected = "#EXTINF:0.000001,\n" \
|
|
99
|
+
"#EXT-X-PROGRAM-DATE-TIME:2020-11-25T20:27:00Z\n" \
|
|
100
|
+
'test.ts'
|
|
101
|
+
expect(output).to eq expected
|
|
102
|
+
end
|
|
92
103
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: m3u8
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.8.
|
|
4
|
+
version: 1.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Seth Deckard
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2026-03-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bigdecimal
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
description: Generate and parse m3u8 playlists for HTTP Live Streaming (HLS).
|
|
14
28
|
email:
|
|
15
29
|
- seth@deckard.me
|