playlist 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.md +21 -0
- data/README.md +90 -0
- data/Rakefile +10 -0
- data/lib/playlist/contributor.rb +31 -0
- data/lib/playlist/format/m3u.rb +39 -0
- data/lib/playlist/format/simple_text.rb +39 -0
- data/lib/playlist/format/xspf.rb +62 -0
- data/lib/playlist/format.rb +6 -0
- data/lib/playlist/track.rb +147 -0
- data/lib/playlist/version.rb +4 -0
- data/lib/playlist.rb +57 -0
- data/playlist.gemspec +28 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cbc27126439999045463cfa6de6ba50f75eb1864
|
4
|
+
data.tar.gz: 03110b81cb035d0b4b2685a64bc1fd41c8d4f414
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 56fe2477c106da8550f666694fc90185c496ad74eb42ff2ab03f695e4f8063b150ae31c8019fc1f11bdee0b192fbbbcbadd555137037df74c47c38399260c09a
|
7
|
+
data.tar.gz: 77d78fb8dd7f5d802407ed1058f54de4264c18549278d7c91b426981319b6f6b63a06ea2f83dff37f34b13bde2d51c8f4ea123b3ca754797e23a56b76b1fef61
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.0
|
3
|
+
Exclude:
|
4
|
+
- 'vendor/**/*'
|
5
|
+
|
6
|
+
Style/GuardClause:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Style/HashSyntax:
|
10
|
+
EnforcedStyle: hash_rockets
|
11
|
+
|
12
|
+
Style/MutableConstant:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Style/SymbolArray:
|
16
|
+
EnforcedStyle: brackets
|
17
|
+
|
18
|
+
Style/ClassAndModuleChildren:
|
19
|
+
EnforcedStyle: compact
|
20
|
+
|
21
|
+
MethodLength:
|
22
|
+
Max: 20
|
23
|
+
|
24
|
+
Metrics/AbcSize:
|
25
|
+
Max: 20
|
26
|
+
|
27
|
+
# Allow long blocks in rspec
|
28
|
+
Metrics/BlockLength:
|
29
|
+
ExcludedMethods: ['describe', 'context']
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Nicholas J Humfrey
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
[](https://travis-ci.org/njh/ruby-playlist)
|
2
|
+
|
3
|
+
# Playlist
|
4
|
+
|
5
|
+
This ruby gem allows you to create and manipulate playlists of musical tracks.
|
6
|
+
|
7
|
+
It supports parsing and generating playlists in the following formats:
|
8
|
+
|
9
|
+
* M3U
|
10
|
+
* XSPF
|
11
|
+
* A simple human readable format
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'playlist'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install playlist
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
For full details, please see the [API Documentation](https://www.rubydoc.info/gems/playlist/).
|
32
|
+
|
33
|
+
### Creating a Playlist
|
34
|
+
|
35
|
+
The `playlist` gem provides data model classes for creating and manipulating
|
36
|
+
playlists and music metadata in ruby.
|
37
|
+
|
38
|
+
Playlists can be constructed by passing a list of attributes to the constructor or by setting the attributes directly:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
playlist = Playlist.new(:title => "My awesome playlist")
|
42
|
+
playlist.annotation = "Each week I add best tracks I can think of."
|
43
|
+
playlist.add_track(
|
44
|
+
:performer => "Jon Hopkins",
|
45
|
+
:title => "Everything Connected"
|
46
|
+
)
|
47
|
+
|
48
|
+
track = Playlist::Track.new(:title => "Get Your Shirt")
|
49
|
+
track.add_contributor(:name => "Underworld", :role => :performer)
|
50
|
+
track.add_contributor(:name => "Iggy Pop", :role => :performer)
|
51
|
+
playlist.add_track(track)
|
52
|
+
```
|
53
|
+
|
54
|
+
### Parsing a playlist file
|
55
|
+
|
56
|
+
The `playlist` gem supports a number of different playlist file formats.
|
57
|
+
Here is an example of parsing a M3U file:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
File.open("playlist.m3u") do |file|
|
61
|
+
playlist = Playlist::Format::M3U.parse(file)
|
62
|
+
puts "The playlist contains #{playlist.tracks.count} tracks"
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
### Generating a playlist file
|
67
|
+
|
68
|
+
Having created a `Playlist` object, it can be converted to a playlist file using:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
File.open("playlist.m3u", "wb") do |file|
|
72
|
+
file.write Playlist::Format::M3U.generate(playlist)
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
|
77
|
+
## Development
|
78
|
+
|
79
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
|
80
|
+
|
81
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
82
|
+
|
83
|
+
## Contributing
|
84
|
+
|
85
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/njh/ruby-playlist.
|
86
|
+
|
87
|
+
|
88
|
+
## License
|
89
|
+
|
90
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Data model class that represents a contributor to a track.
|
2
|
+
# A Contrutor can be a person, or a organisation
|
3
|
+
# (such an band, choir or orchestra).
|
4
|
+
class Playlist::Contributor
|
5
|
+
# The name of the contributor
|
6
|
+
# @return [String]
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
# The role of the contribrition to the track
|
10
|
+
#
|
11
|
+
# Recommended values for role:
|
12
|
+
# :performer
|
13
|
+
# :composer
|
14
|
+
# :arranger
|
15
|
+
# :lyricist
|
16
|
+
# @return [Symbol]
|
17
|
+
attr_accessor :role
|
18
|
+
|
19
|
+
# Create a new Contributor
|
20
|
+
def initialize(attr = nil)
|
21
|
+
if attr.is_a?(Hash)
|
22
|
+
attr.each_pair do |key, value|
|
23
|
+
send("#{key}=", value)
|
24
|
+
end
|
25
|
+
elsif attr.is_a?(String)
|
26
|
+
self.name = attr
|
27
|
+
end
|
28
|
+
|
29
|
+
yield(self) if block_given?
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Module to parse and generate M3U playlists
|
2
|
+
module Playlist::Format::M3U
|
3
|
+
class << self
|
4
|
+
# Parse a M3U 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
|
+
Playlist.new do |playlist|
|
10
|
+
track = Playlist::Track.new
|
11
|
+
input.each_line do |line|
|
12
|
+
if line =~ /^#EXTINF:(-?\d+),\s*(.+?)\s*-\s*(.+?)\s*$/
|
13
|
+
track.duration = Regexp.last_match(1)
|
14
|
+
track.creator = Regexp.last_match(2)
|
15
|
+
track.title = Regexp.last_match(3)
|
16
|
+
else
|
17
|
+
if line =~ /^[^#]\S+.+\s*$/
|
18
|
+
track.location = line.strip
|
19
|
+
playlist.add_track(track)
|
20
|
+
end
|
21
|
+
track = Playlist::Track.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Generate a M3U file from a [Playlist]
|
28
|
+
# @param playlist [Playlist] the playlist to be converted to M3U
|
29
|
+
# @return [String] M3U as a string
|
30
|
+
def generate(playlist)
|
31
|
+
text = "#EXTM3U\n"
|
32
|
+
playlist.tracks.each do |t|
|
33
|
+
text += "#EXTINF:#{t.duration.to_i},#{t.artist} - #{t.title}\n"
|
34
|
+
text += "#{t.location}\n"
|
35
|
+
end
|
36
|
+
text
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Module to parse and generate playlists with one line per track
|
2
|
+
module Playlist::Format::SimpleText
|
3
|
+
class << self
|
4
|
+
# Parse a human readable list of tracks 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
|
+
Playlist.new do |playlist|
|
10
|
+
input.each_line do |line|
|
11
|
+
next if line =~ /^#/
|
12
|
+
|
13
|
+
track = parse_line(line.strip)
|
14
|
+
playlist.tracks << track unless track.nil?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Parse a single line from a playlist into a Track obect
|
20
|
+
# @param line [String] any object that responds to #each_line
|
21
|
+
# @return [Track] a new Track object
|
22
|
+
def parse_line(line)
|
23
|
+
if line =~ /^(\d{1,2}[:.]\d{1,2}([:.]\d{1,2})?)?\s*(.+?) - (.+?)$/
|
24
|
+
Playlist::Track.new(
|
25
|
+
:start_time => Regexp.last_match(1),
|
26
|
+
:creator => Regexp.last_match(3).strip,
|
27
|
+
:title => Regexp.last_match(4).strip
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generate a human readable list of tracks from a Playlist
|
33
|
+
# @param playlist [Playlist] the playlist
|
34
|
+
# @return [String] the playlist with one line per track
|
35
|
+
def generate(playlist)
|
36
|
+
playlist.tracks.map { |t| "#{t.artist} - #{t.title}" }.join("\n") + "\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
# Module to parse and generate XSPF playlists
|
4
|
+
module Playlist::Format::XSPF
|
5
|
+
class << self
|
6
|
+
# Parse a XSPF file into a new Playlist object
|
7
|
+
# @param input [String, IO] the source of the XSPF file
|
8
|
+
# @return [Playlist] a new Playlist object
|
9
|
+
def parse(input)
|
10
|
+
Playlist.new do |playlist|
|
11
|
+
doc = Nokogiri::XML(input)
|
12
|
+
playlist.title = inner_text_or_nil(doc, '/xmlns:playlist/xmlns:title')
|
13
|
+
doc.xpath('/xmlns:playlist/xmlns:trackList/xmlns:track').each do |track|
|
14
|
+
playlist.tracks << parse_track(track)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generate a XSPF file from a Playlist object
|
20
|
+
# @param playlist [Playlist] the playlist
|
21
|
+
# @return [String] the XSPF playlist as a String
|
22
|
+
def generate(playlist)
|
23
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
24
|
+
xml.playlist(:version => 1, :xmlns => 'http://xspf.org/ns/0/') do
|
25
|
+
xml.title(playlist.title) unless playlist.title.nil?
|
26
|
+
xml.trackList do
|
27
|
+
playlist.tracks.each { |track| generate_track(xml, track) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
builder.to_xml
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def parse_track(doc)
|
37
|
+
Playlist::Track.new do |track|
|
38
|
+
track.creator = inner_text_or_nil(doc, 'xmlns:creator')
|
39
|
+
track.title = inner_text_or_nil(doc, 'xmlns:title')
|
40
|
+
track.location = inner_text_or_nil(doc, 'xmlns:location')
|
41
|
+
if (duration = inner_text_or_nil(doc, 'xmlns:duration'))
|
42
|
+
track.duration = duration.to_f / 1000
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_track(xml, track)
|
48
|
+
xml.track do
|
49
|
+
xml.location(track.location) unless track.location.nil?
|
50
|
+
xml.title(track.title) unless track.title.nil?
|
51
|
+
xml.creator(track.creator) unless track.creator.nil?
|
52
|
+
xml.duration((track.duration * 1000).to_i) unless track.duration.nil?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
## FIXME: how to do this better?
|
57
|
+
def inner_text_or_nil(doc, path)
|
58
|
+
element = doc.at_xpath(path)
|
59
|
+
element.inner_text unless element.nil?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# Data model class that represents a single track.
|
2
|
+
class Playlist::Track
|
3
|
+
# A URI (or filename) to the location of the file
|
4
|
+
attr_accessor :location
|
5
|
+
|
6
|
+
# The title of the track
|
7
|
+
# @return [String]
|
8
|
+
attr_accessor :title
|
9
|
+
|
10
|
+
# The name of the album that the track came from
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :album
|
13
|
+
|
14
|
+
# The number of the track on the album it came from
|
15
|
+
# @return [Integer]
|
16
|
+
attr_accessor :track_number
|
17
|
+
|
18
|
+
# The side of disc if the track came from a vinyl album (eg A/B)
|
19
|
+
# @return [String]
|
20
|
+
attr_accessor :side
|
21
|
+
|
22
|
+
# The name of the record label that published the track/album
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :record_label
|
25
|
+
|
26
|
+
# The name of the publisher that published the score/lyrics of the song
|
27
|
+
# @return [String]
|
28
|
+
attr_accessor :publisher
|
29
|
+
|
30
|
+
# The time a track starts playing at, in seconds.
|
31
|
+
# May be a Float to include fractions of a second.
|
32
|
+
# @return [Integer, Float]
|
33
|
+
attr_accessor :start_time
|
34
|
+
|
35
|
+
# The duration of the track in seconds.
|
36
|
+
# May be a Float to include fractions of a second.
|
37
|
+
# @return [Integer, Float]
|
38
|
+
attr_reader :duration
|
39
|
+
|
40
|
+
# Get the array of the contributors to this Track
|
41
|
+
# @return [Array<Contributor>] an array of tracks in the playlist
|
42
|
+
attr_reader :contributors
|
43
|
+
|
44
|
+
# Create a new Track
|
45
|
+
# @param attr [Hash] a hash of attibute values to set
|
46
|
+
def initialize(attr = {})
|
47
|
+
@contributors = []
|
48
|
+
attr.each_pair do |key, value|
|
49
|
+
send("#{key}=", value)
|
50
|
+
end
|
51
|
+
|
52
|
+
yield(self) if block_given?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get a concatinated list of contributors names with no role
|
56
|
+
# @return [String]
|
57
|
+
def creator
|
58
|
+
contributor_names(nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set the name of the contributor with no role
|
62
|
+
# Removes any existing contributors with no role
|
63
|
+
# @param name [String] the name the contributor
|
64
|
+
def creator=(name)
|
65
|
+
replace_contributor(nil, name)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get a conactinated list of performers for this track
|
69
|
+
# If there are no performers, return contributors with no role
|
70
|
+
# @return [String]
|
71
|
+
def performer
|
72
|
+
contributor_names(:performer) || contributor_names(nil)
|
73
|
+
end
|
74
|
+
alias artist performer
|
75
|
+
|
76
|
+
# Set the name of the track performer
|
77
|
+
# Removes any existing performers
|
78
|
+
# @param name [String] the name the performer
|
79
|
+
def performer=(name)
|
80
|
+
replace_contributor(:performer, name)
|
81
|
+
end
|
82
|
+
alias artist= performer=
|
83
|
+
|
84
|
+
# Set the duration of the track
|
85
|
+
# If the duration is 0 or -1, then the duration is set to nil
|
86
|
+
# @param seconds [Numeric] the duration of the track in seconds
|
87
|
+
def duration=(seconds)
|
88
|
+
if seconds.is_a?(Numeric)
|
89
|
+
@duration = seconds
|
90
|
+
else
|
91
|
+
seconds = seconds.to_s
|
92
|
+
@duration = if seconds =~ /\./
|
93
|
+
seconds.to_f
|
94
|
+
else
|
95
|
+
seconds.to_i
|
96
|
+
end
|
97
|
+
end
|
98
|
+
@duration = nil if [0, -1].include?(@duration)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Add a contributor to the Track
|
102
|
+
# @param args [Contributor, Hash] either a Contributor object or
|
103
|
+
# a Hash of attributes to creatre a new contributor
|
104
|
+
def add_contributor(args)
|
105
|
+
@contributors << if args.is_a?(Playlist::Contributor)
|
106
|
+
args
|
107
|
+
else
|
108
|
+
Playlist::Contributor.new(args)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# First deletes any contribitors with same role, then adds a new contributor
|
113
|
+
# @param role [Symbol] the role of the new contributor
|
114
|
+
# @param name [String] the name of the new contributor
|
115
|
+
def replace_contributor(role, name)
|
116
|
+
@contributors.delete_if { |c| c.role == role }
|
117
|
+
add_contributor(:role => role, :name => name)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get a concatinated list of contributor names for a specific role
|
121
|
+
# @param role [Symbol] the role of the new contributor
|
122
|
+
# Use :any to concatinate all contributor names
|
123
|
+
# @return [String]
|
124
|
+
def contributor_names(role = :any)
|
125
|
+
filtered = if role == :any
|
126
|
+
@contributors
|
127
|
+
else
|
128
|
+
@contributors.find_all { |c| c.role == role }
|
129
|
+
end
|
130
|
+
if filtered.count == 1
|
131
|
+
filtered.first.name
|
132
|
+
elsif filtered.count >= 2
|
133
|
+
filtered[0..-2].map(&:name).join(', ') +
|
134
|
+
' & ' + filtered.last.name
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Get all the attributes of the track object as a Hash
|
139
|
+
# @return [Hash]
|
140
|
+
def to_h
|
141
|
+
Hash[
|
142
|
+
instance_variables.map do |v|
|
143
|
+
[v.to_s[1..-1].to_sym, instance_variable_get(v)]
|
144
|
+
end
|
145
|
+
]
|
146
|
+
end
|
147
|
+
end
|
data/lib/playlist.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'playlist/version'
|
2
|
+
|
3
|
+
# Data model class that for a single playlist.
|
4
|
+
class Playlist
|
5
|
+
# The title of the playlist
|
6
|
+
# @return [String]
|
7
|
+
attr_accessor :title
|
8
|
+
|
9
|
+
# The name of the creator of this playlist
|
10
|
+
# @return [String]
|
11
|
+
attr_accessor :creator
|
12
|
+
|
13
|
+
# A description/synopsis of the playlist
|
14
|
+
# @return [String]
|
15
|
+
attr_accessor :annotation
|
16
|
+
|
17
|
+
# A URL to get more inforamtion about this playlist
|
18
|
+
# @return [String]
|
19
|
+
attr_accessor :info_url
|
20
|
+
|
21
|
+
# A link to the license / terms of use for this playlist
|
22
|
+
# @return [String]
|
23
|
+
attr_accessor :license
|
24
|
+
|
25
|
+
# Get the array that contains the list of track for this playlist
|
26
|
+
# @return [Array<Track>] an array of tracks in the playlist
|
27
|
+
attr_reader :tracks
|
28
|
+
|
29
|
+
# Create a new Playlist
|
30
|
+
# @param attr [Hash] a hash of attibute values to set
|
31
|
+
def initialize(attr = {})
|
32
|
+
@tracks = []
|
33
|
+
attr.each_pair do |key, value|
|
34
|
+
send("#{key}=", value)
|
35
|
+
end
|
36
|
+
|
37
|
+
yield(self) if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add a track to the playlist
|
41
|
+
# @param args [Track, Hash] either a Track object or
|
42
|
+
# a Hash of attributes to creatre a new Track
|
43
|
+
def add_track(args)
|
44
|
+
@tracks << (args.is_a?(Track) ? args : Track.new(args))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the total duration of this playlist
|
48
|
+
# If any tracks on the playlist don't have a duation, then they are ignored
|
49
|
+
# @return [Integer, Float]
|
50
|
+
def duration
|
51
|
+
@tracks.map(&:duration).compact.inject(:+)
|
52
|
+
end
|
53
|
+
|
54
|
+
autoload :Contributor, 'playlist/contributor'
|
55
|
+
autoload :Track, 'playlist/track'
|
56
|
+
autoload :Format, 'playlist/format'
|
57
|
+
end
|
data/playlist.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
2
|
+
require 'playlist/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'playlist'
|
6
|
+
spec.version = Playlist::VERSION
|
7
|
+
spec.authors = ['Nicholas Humfrey']
|
8
|
+
spec.email = ['njh@aelius.com']
|
9
|
+
|
10
|
+
spec.summary = 'Convert playlists between different formats'
|
11
|
+
spec.homepage = 'https://github.com/njh/ruby-playlist'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
15
|
+
f.match(%r{^(test|spec|features)/})
|
16
|
+
end
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '> 1.13'
|
22
|
+
spec.add_development_dependency 'equivalent-xml', '~> 0.6.0'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.2.2'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.7.0'
|
25
|
+
spec.add_development_dependency 'rubocop', '~> 0.50.0'
|
26
|
+
spec.add_development_dependency 'simplecov', '~> 0.9.2'
|
27
|
+
spec.add_development_dependency 'yard', '~> 0.9.14'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: playlist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Humfrey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: equivalent-xml
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 10.2.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 10.2.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.7.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.7.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.50.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.50.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.9.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.9.14
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.9.14
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- njh@aelius.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rubocop.yml"
|
120
|
+
- ".travis.yml"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.md
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- lib/playlist.rb
|
126
|
+
- lib/playlist/contributor.rb
|
127
|
+
- lib/playlist/format.rb
|
128
|
+
- lib/playlist/format/m3u.rb
|
129
|
+
- lib/playlist/format/simple_text.rb
|
130
|
+
- lib/playlist/format/xspf.rb
|
131
|
+
- lib/playlist/track.rb
|
132
|
+
- lib/playlist/version.rb
|
133
|
+
- playlist.gemspec
|
134
|
+
homepage: https://github.com/njh/ruby-playlist
|
135
|
+
licenses:
|
136
|
+
- MIT
|
137
|
+
metadata: {}
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
requirements: []
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 2.4.5
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: Convert playlists between different formats
|
158
|
+
test_files: []
|