playlist 1.1.0 → 1.2.0
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 +5 -5
- data/.rubocop.yml +14 -3
- data/.travis.yml +1 -1
- data/README.md +2 -0
- data/lib/playlist.rb +5 -0
- data/lib/playlist/format.rb +1 -0
- data/lib/playlist/format/pls.rb +91 -0
- data/lib/playlist/format/xspf.rb +32 -8
- data/lib/playlist/track.rb +8 -0
- data/lib/playlist/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 81dea6b42315190f6066d99551de62d84752aacf44fb39721fbea24e6713c4e3
|
4
|
+
data.tar.gz: b7e528d0db40b684efab812c09a7dcf566b44d468f058035037094c84f99bb1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6b9a2047b4bd0093b2f22053a2a8ac247a711fa5abffbfc838aed9b884e2011eb156ba88f65d28da7f4f1e9446807d8f2b422b75cbb4a42c846a530e1fcaf43
|
7
|
+
data.tar.gz: '019d2491fdac856319d36ceb3941d83eac7139a5679970b8fd8de51da384ddff8eb3941655f1b0d5c1eb3dd90489290ce601b3047b8dfcd4de1b07852abad7d0'
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.3
|
3
3
|
Exclude:
|
4
4
|
- 'vendor/**/*'
|
5
5
|
|
@@ -12,17 +12,28 @@ Style/HashSyntax:
|
|
12
12
|
Style/MutableConstant:
|
13
13
|
Enabled: false
|
14
14
|
|
15
|
+
Style/FrozenStringLiteralComment:
|
16
|
+
Enabled: false
|
17
|
+
|
15
18
|
Style/SymbolArray:
|
16
19
|
EnforcedStyle: brackets
|
17
20
|
|
18
21
|
Style/ClassAndModuleChildren:
|
19
22
|
EnforcedStyle: compact
|
20
23
|
|
21
|
-
|
24
|
+
# Not available in older rubies
|
25
|
+
Style/SafeNavigation:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
# Disabled because it makes the code longer, more repetitive
|
29
|
+
Style/FormatStringToken:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Metrics/MethodLength:
|
22
33
|
Max: 20
|
23
34
|
|
24
35
|
Metrics/AbcSize:
|
25
|
-
Max:
|
36
|
+
Max: 25
|
26
37
|
|
27
38
|
# Allow long blocks in rspec
|
28
39
|
Metrics/BlockLength:
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
data/lib/playlist.rb
CHANGED
@@ -27,6 +27,10 @@ class Playlist
|
|
27
27
|
# @return [String]
|
28
28
|
attr_accessor :license
|
29
29
|
|
30
|
+
# URI of an image associated with this playlist
|
31
|
+
# @return [String]
|
32
|
+
attr_accessor :image
|
33
|
+
|
30
34
|
# Get a hash of identifier for this playlist
|
31
35
|
# Identifiers can either be Strings or URIs
|
32
36
|
# @return [Hash] an hash of identifiers
|
@@ -68,6 +72,7 @@ class Playlist
|
|
68
72
|
time = tracks.first.start_time || 0
|
69
73
|
tracks.each do |track|
|
70
74
|
break if track.duration.nil?
|
75
|
+
|
71
76
|
time = (track.start_time ||= time)
|
72
77
|
time += track.duration
|
73
78
|
end
|
data/lib/playlist/format.rb
CHANGED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Module to parse and generate PLS playlists
|
2
|
+
module Playlist::Format::PLS
|
3
|
+
class << self
|
4
|
+
# Parse a PLS file into a [Playlist]
|
5
|
+
# @param input any object that responds to #each_line
|
6
|
+
# (either a String or a IO object)
|
7
|
+
# @return [Playlist] a new Playlist object
|
8
|
+
def parse(input)
|
9
|
+
tracks = parse_lines_to_array(input)
|
10
|
+
|
11
|
+
# Now convert to objects
|
12
|
+
array_to_object(tracks)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Generate a PLS file from a [Playlist]
|
16
|
+
# @param playlist [Playlist] the playlist to be converted to PLS
|
17
|
+
# @return [String] PLS as a string
|
18
|
+
def generate(playlist)
|
19
|
+
text = "[playlist]\n\n"
|
20
|
+
playlist.tracks.each_with_index do |t, index|
|
21
|
+
index += 1
|
22
|
+
duration = (t.duration / 1000).round
|
23
|
+
text += "File#{index}=#{t.location}\n"
|
24
|
+
if t.creator && t.title
|
25
|
+
text += "Title#{index}=#{t.creator} - #{t.title}\n"
|
26
|
+
elsif t.title
|
27
|
+
text += "Title#{index}=#{t.title}\n"
|
28
|
+
end
|
29
|
+
text += "Length#{index}=#{duration}\n"
|
30
|
+
text += "\n"
|
31
|
+
end
|
32
|
+
text += "NumberOfEntries=#{playlist.tracks.count}\n"
|
33
|
+
text += "Version=2\n"
|
34
|
+
text
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def parse_line(tracks, line)
|
40
|
+
if (matches = line.match(/^([a-z]+)(\d+)=(.+)$/i))
|
41
|
+
key = matches[1].downcase.to_sym
|
42
|
+
num = matches[2].to_i - 1
|
43
|
+
tracks[num] ||= {}
|
44
|
+
tracks[num][key] = matches[3]
|
45
|
+
elsif (matches = line.match(/^NumberOfEntries=(\d+)$/))
|
46
|
+
if matches[1].to_i != tracks.count
|
47
|
+
raise 'PLS parse error: NumberOfEntries is incorrect'
|
48
|
+
end
|
49
|
+
elsif (matches = line.match(/^Version=(\d+)$/))
|
50
|
+
if matches[1] != '2'
|
51
|
+
raise "PLS file version #{version} is not supported"
|
52
|
+
end
|
53
|
+
else
|
54
|
+
warn "Unable to parse line: #{line}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_lines_to_array(input)
|
59
|
+
tracks = []
|
60
|
+
input.each_line.with_index do |line, index|
|
61
|
+
line.strip!
|
62
|
+
if index.zero?
|
63
|
+
if line == '[playlist]'
|
64
|
+
next
|
65
|
+
else
|
66
|
+
raise 'PLS parse error: first line is not [playlist]'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
parse_line(tracks, line) unless line.empty?
|
70
|
+
end
|
71
|
+
tracks
|
72
|
+
end
|
73
|
+
|
74
|
+
def array_to_object(tracks)
|
75
|
+
Playlist.new do |playlist|
|
76
|
+
tracks.each do |track|
|
77
|
+
obj = Playlist::Track.new
|
78
|
+
obj.location = track[:file] unless track[:file].nil?
|
79
|
+
obj.duration = track[:length].to_i * 1000 unless track[:length].nil?
|
80
|
+
if (matches = track[:title].match(/^(.+) - (.+)$/))
|
81
|
+
obj.creator = matches[1]
|
82
|
+
obj.title = matches[2]
|
83
|
+
else
|
84
|
+
obj.title = track[:title]
|
85
|
+
end
|
86
|
+
playlist.add_track(obj)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/playlist/format/xspf.rb
CHANGED
@@ -14,9 +14,12 @@ module Playlist::Format::XSPF
|
|
14
14
|
Playlist.new do |playlist|
|
15
15
|
doc = Nokogiri::XML(input)
|
16
16
|
playlist.title = doc.content_at('/xmlns:playlist/xmlns:title')
|
17
|
+
playlist.creator = doc.content_at('/xmlns:playlist/xmlns:creator')
|
17
18
|
playlist.description = doc.content_at(
|
18
19
|
'/xmlns:playlist/xmlns:annotation'
|
19
20
|
)
|
21
|
+
playlist.image = doc.content_at('/xmlns:playlist/xmlns:image')
|
22
|
+
playlist.info_url = doc.content_at('/xmlns:playlist/xmlns:info')
|
20
23
|
doc.xpath('/xmlns:playlist/xmlns:trackList/xmlns:track').each do |track|
|
21
24
|
playlist.tracks << parse_track(track)
|
22
25
|
end
|
@@ -29,8 +32,14 @@ module Playlist::Format::XSPF
|
|
29
32
|
def generate(playlist)
|
30
33
|
builder = Nokogiri::XML::Builder.new do |xml|
|
31
34
|
xml.playlist(:version => 1, :xmlns => 'http://xspf.org/ns/0/') do
|
32
|
-
|
33
|
-
|
35
|
+
build_xml_unless_nil(
|
36
|
+
xml,
|
37
|
+
:title => playlist.title,
|
38
|
+
:creator => playlist.creator,
|
39
|
+
:annotation => playlist.description,
|
40
|
+
:image => playlist.image,
|
41
|
+
:info => playlist.info_url
|
42
|
+
)
|
34
43
|
xml.trackList do
|
35
44
|
playlist.tracks.each { |track| generate_track(xml, track) }
|
36
45
|
end
|
@@ -43,21 +52,36 @@ module Playlist::Format::XSPF
|
|
43
52
|
|
44
53
|
def parse_track(doc)
|
45
54
|
Playlist::Track.new do |track|
|
46
|
-
track.creator = doc.content_at('./xmlns:creator')
|
47
|
-
track.title = doc.content_at('./xmlns:title')
|
48
55
|
track.location = doc.content_at('./xmlns:location')
|
56
|
+
track.title = doc.content_at('./xmlns:title')
|
57
|
+
track.creator = doc.content_at('./xmlns:creator')
|
49
58
|
if (duration = doc.content_at('./xmlns:duration'))
|
50
59
|
track.duration = duration.to_i
|
51
60
|
end
|
61
|
+
track.album = doc.content_at('./xmlns:album')
|
62
|
+
track.description = doc.content_at('./xmlns:annotation')
|
63
|
+
track.image = doc.content_at('./xmlns:image')
|
52
64
|
end
|
53
65
|
end
|
54
66
|
|
55
67
|
def generate_track(xml, track)
|
56
68
|
xml.track do
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
69
|
+
build_xml_unless_nil(
|
70
|
+
xml,
|
71
|
+
:location => track.location,
|
72
|
+
:title => track.title,
|
73
|
+
:creator => track.creator,
|
74
|
+
:duration => track.duration,
|
75
|
+
:album => track.album,
|
76
|
+
:annotation => track.description,
|
77
|
+
:image => track.image
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_xml_unless_nil(xml, hash)
|
83
|
+
hash.each_pair do |key, value|
|
84
|
+
xml.send(key, value) unless value.nil?
|
61
85
|
end
|
62
86
|
end
|
63
87
|
end
|
data/lib/playlist/track.rb
CHANGED
@@ -11,6 +11,10 @@ class Playlist::Track
|
|
11
11
|
# @return [String]
|
12
12
|
attr_accessor :album
|
13
13
|
|
14
|
+
# A description/annotation/synopsis of the track
|
15
|
+
# @return [String]
|
16
|
+
attr_accessor :description
|
17
|
+
|
14
18
|
# The catalogue number of the album that the track came from
|
15
19
|
# Also known as the UPC/EAN code
|
16
20
|
# @return [String]
|
@@ -51,6 +55,10 @@ class Playlist::Track
|
|
51
55
|
# @return [Array<Contributor>] an array of tracks in the playlist
|
52
56
|
attr_reader :contributors
|
53
57
|
|
58
|
+
# URI of an image associated with this Track
|
59
|
+
# @return [String]
|
60
|
+
attr_accessor :image
|
61
|
+
|
54
62
|
# Create a new Track
|
55
63
|
# @param attr [Hash] a hash of attibute values to set
|
56
64
|
def initialize(attr = {})
|
data/lib/playlist/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: playlist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Humfrey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- lib/playlist/format.rb
|
143
143
|
- lib/playlist/format/cue.rb
|
144
144
|
- lib/playlist/format/m3u.rb
|
145
|
+
- lib/playlist/format/pls.rb
|
145
146
|
- lib/playlist/format/simple_text.rb
|
146
147
|
- lib/playlist/format/xspf.rb
|
147
148
|
- lib/playlist/track.rb
|
@@ -167,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
168
|
version: '0'
|
168
169
|
requirements: []
|
169
170
|
rubyforge_project:
|
170
|
-
rubygems_version: 2.
|
171
|
+
rubygems_version: 2.7.6.2
|
171
172
|
signing_key:
|
172
173
|
specification_version: 4
|
173
174
|
summary: Convert playlists between different formats
|