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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 30be0088143707327ec29c8888bd04f94ee2ff22
4
- data.tar.gz: 1c462de277427d226a81ce130c060910ac74c525
2
+ SHA256:
3
+ metadata.gz: 81dea6b42315190f6066d99551de62d84752aacf44fb39721fbea24e6713c4e3
4
+ data.tar.gz: b7e528d0db40b684efab812c09a7dcf566b44d468f058035037094c84f99bb1f
5
5
  SHA512:
6
- metadata.gz: 53b751fa9ad238e6acb13c0287e84ec4387a86d406d3a6ade773eb2bad5d1571b656328ac336a6cd5f24932ed4e609be4dd283cac437b57200293d290ebd54cc
7
- data.tar.gz: 21563296d9604407988d425bc9002b830bee0be57c118982ffa32408fefc0e04e87de29d506be7a7e85b560cdefc4cdc66143a6969173bbc74b036ced80c841a
6
+ metadata.gz: f6b9a2047b4bd0093b2f22053a2a8ac247a711fa5abffbfc838aed9b884e2011eb156ba88f65d28da7f4f1e9446807d8f2b422b75cbb4a42c846a530e1fcaf43
7
+ data.tar.gz: '019d2491fdac856319d36ceb3941d83eac7139a5679970b8fd8de51da384ddff8eb3941655f1b0d5c1eb3dd90489290ce601b3047b8dfcd4de1b07852abad7d0'
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.0
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
- MethodLength:
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: 20
36
+ Max: 25
26
37
 
27
38
  # Allow long blocks in rspec
28
39
  Metrics/BlockLength:
@@ -2,4 +2,4 @@ sudo: false
2
2
  language: ruby
3
3
  rvm:
4
4
  - 2.2.2
5
- before_install: gem install bundler -v 1.13.7
5
+ - 2.5.2
data/README.md CHANGED
@@ -7,8 +7,10 @@ This ruby gem allows you to create and manipulate playlists of musical tracks.
7
7
  It supports parsing and generating playlists in the following formats:
8
8
 
9
9
  * M3U
10
+ * PLS
10
11
  * XSPF
11
12
  * A simple human readable format
13
+ * Cue Sheet
12
14
 
13
15
  ## Installation
14
16
 
@@ -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
@@ -2,6 +2,7 @@
2
2
  module Playlist::Format
3
3
  autoload :Cue, 'playlist/format/cue'
4
4
  autoload :M3U, 'playlist/format/m3u'
5
+ autoload :PLS, 'playlist/format/pls'
5
6
  autoload :SimpleText, 'playlist/format/simple_text'
6
7
  autoload :XSPF, 'playlist/format/xspf'
7
8
  end
@@ -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
@@ -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
- xml.title(playlist.title) unless playlist.title.nil?
33
- xml.annotation(playlist.description) unless playlist.description.nil?
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
- xml.location(track.location) unless track.location.nil?
58
- xml.title(track.title) unless track.title.nil?
59
- xml.creator(track.creator) unless track.creator.nil?
60
- xml.duration(track.duration) unless track.duration.nil?
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
@@ -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 = {})
@@ -1,4 +1,4 @@
1
1
  class Playlist
2
2
  # The version number of the Playlist Ruby gem
3
- VERSION = '1.1.0'
3
+ VERSION = '1.2.0'
4
4
  end
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.1.0
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: 2018-08-03 00:00:00.000000000 Z
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.4.5
171
+ rubygems_version: 2.7.6.2
171
172
  signing_key:
172
173
  specification_version: 4
173
174
  summary: Convert playlists between different formats