playlist 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|