audio_rating 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 04241f9e45252fddebb384470955d118aeca96df6f7d82cac83fbddc220b0fb1
4
+ data.tar.gz: 26210a06a5ef426c31b9e64241e960fd7fc7ce851f05c05fdb0fdf8cdca799b1
5
+ SHA512:
6
+ metadata.gz: 777421a49368ec2650dd4aa39539bf8e0f781b9a6d69b473541cca872cf2a02f04274a3e08f25e5482411886b9d4803af9f07552c7f452c6cb2a2bf0c3006f6b
7
+ data.tar.gz: 0537d3a65f570f8ad9c1fffdc85711b4f13c10e0cd3e3e5490033b4cc851a07e0ffe67f1329dd4b8681aa6ad6684fd704bc3f2f1879e1c5222bc7fe49a362d44
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --private
2
+ --readme README.md
3
+ -
4
+ CHANGELOG.md
5
+ LICENSE
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2023-08-08
11
+
12
+ - Initial release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Hayden
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,77 @@
1
+ # AudioRating
2
+
3
+ Ruby library for reading embedded star-ratings in audio files.
4
+
5
+ Supports file formats: AIFF, FLAC, M4A, MP3, Ogg and WAV.
6
+
7
+ Uses library [TagLib](https://taglib.org/) and Ruby interface [taglib-ruby](https://robinst.github.io/taglib-ruby/).
8
+
9
+ ## Installation
10
+
11
+ Requires TagLib 1.11.1 or higher. Can be installed using:
12
+
13
+ ```shell
14
+ apt-get install libtag1-dev # On Debian/Ubuntu
15
+ dnf install taglib-devel # On Fedora/RHEL
16
+ brew install taglib # On macOS
17
+ ```
18
+
19
+ Install the gem using either:
20
+
21
+ ```shell
22
+ bundle add audio_rating # If using bundler, also adds to Gemfile
23
+ gem install audio_rating # If not, just install
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```ruby
29
+ require 'audio_rating'
30
+
31
+ AudioRating.get 'Shrek (2001)/9. All Star.mp3'
32
+ # => 5
33
+ ```
34
+
35
+ Complete library documentation is available [here](https://rubydoc.info/gems/audio_rating/doc/AudioRating.html).
36
+
37
+ ## Development
38
+
39
+ [Docker Compose](https://docs.docker.com/compose/) allows easy local development on many systems.
40
+
41
+ ### Docker Compose setup
42
+
43
+ Build Debian-12/Ruby-3.2 container and install library gem dependencies:
44
+
45
+ ```shell
46
+ docker compose build runner
47
+ ```
48
+
49
+ Commands can then be ran inside the Docker Compose container.
50
+
51
+ ### Main commands
52
+
53
+ Run unit tests:
54
+
55
+ ```shell
56
+ docker compose run --rm runner rake test
57
+ ```
58
+
59
+ Check code style:
60
+
61
+ ```shell
62
+ docker compose run --rm runner bundle exec rubocop
63
+ ```
64
+
65
+ Generate documentation:
66
+
67
+ ```shell
68
+ docker compose run --rm runner yard
69
+ ```
70
+
71
+ Build gem, publish to RubyGems and push new git tag:
72
+
73
+ ```shell
74
+ docker compose run --rm runner gem build audio_rating.gemspec
75
+ docker compose run --rm runner gem push audio_rating-0.1.0.gem
76
+ git tag -a v0.1.0 -m 'Initial release'
77
+ ```
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for AIFF files.
5
+ module AIFF
6
+ # Get a AIFF file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/RIFF/AIFF/File
10
+ #
11
+ # @param path [String] the AIFF file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::RIFF::AIFF::File.open(path) do |file|
18
+ next unless file&.id3v2_tag?
19
+
20
+ AudioRating::ID3v2.get file.tag
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A library for reading embedded star-ratings in audio files.
4
+ module AudioRating
5
+ # Get an audio file's embedded star-rating metadata if present.
6
+ #
7
+ # Supports file formats: AIFF, FLAC, M4A, MP3, Ogg and WAV.
8
+ #
9
+ # @param path [String] the file path of audio file
10
+ #
11
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
12
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
13
+ # @return [nil] if file not found, or file has no star-rating metadata
14
+ #
15
+ # @example
16
+ # AudioRating.get 'test/data/musicbee/5.mp3'
17
+ # # => 5
18
+ #
19
+ # AudioRating.get '/dev/null'
20
+ # # => nil
21
+ def self.get(path)
22
+ case File.extname(path).downcase
23
+ when '.aiff' then AIFF.get(path)
24
+ when '.flac' then FLAC.get(path)
25
+ when '.m4a' then M4A.get(path)
26
+ when '.mp3' then MP3.get(path)
27
+ when '.ogg' then Ogg.get(path)
28
+ when '.wav' then WAV.get(path)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Maps newer 'Rate' value to star rating.
5
+ RATE_VALUE_TO_STAR_RATING = {
6
+ # Used by:
7
+ # - MusicBee for AIFF/FLAC/MP4/Ogg/Wav
8
+ # - MediaMonkey for FLAC/MP4/Ogg:
9
+ 10 => 0.5,
10
+ 20 => 1,
11
+ 30 => 1.5,
12
+ 40 => 2,
13
+ 50 => 2.5,
14
+ 60 => 3,
15
+ 70 => 3.5,
16
+ 80 => 4,
17
+ 90 => 4.5,
18
+ 100 => 5
19
+ }.freeze
20
+
21
+ # Maps ID3v2 Popularimeter rating value to star rating.
22
+ POPM_VALUE_TO_STAR_RATING = {
23
+ # Whole star format used by:
24
+ # - Windows Media Player for MP3
25
+ # - foobar2000 for AIFF/MP3/WAV
26
+ # - MusicBee for MP3
27
+ # - MediaMonkey for AIFF/MP3
28
+ 1 => 1,
29
+ 64 => 2,
30
+ 128 => 3,
31
+ 196 => 4,
32
+ 255 => 5,
33
+ # Half-star format used by:
34
+ # - MusicBee for MP3
35
+ # - MediaMonkey for AIFF/MP3:
36
+ 13 => 0.5,
37
+ 54 => 1.5,
38
+ 118 => 2.5,
39
+ 186 => 3.5,
40
+ 242 => 4.5
41
+ }.freeze
42
+
43
+ # Constant mappings as tested in Windows 10 software:
44
+ # - Windows Media Player (WMP) 12.0.19041.3271
45
+ # - foobar2000 version 1.3.9
46
+ # - MusicBee version 3.5.8447
47
+ # - MediaMonkey version 5.0.4.2690
48
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for FLAC files.
5
+ module FLAC
6
+ # Get a FLAC file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/FLAC/File
10
+ #
11
+ # @param path [String] the FLAC file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::FLAC::File.open(path) do |file|
18
+ next unless file&.valid? && file&.xiph_comment?
19
+
20
+ fields = file.xiph_comment.field_list_map
21
+ next unless fields.key? 'RATING'
22
+
23
+ rating = fields['RATING'].first.to_i
24
+ return rating if rating <= 5 # foobar2000 sets <= 5
25
+
26
+ # MusicBee & MediaMonkey sets > 5
27
+ RATE_VALUE_TO_STAR_RATING[rating] if rating > 5
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for ID3v2 tags, used by AIFF, MP3 and WAV files.
5
+ module ID3v2
6
+ # Get an ID3v2 tag's star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/ID3v2/PopularimeterFrame
10
+ #
11
+ # @param tag [TagLib::ID3v2::Tag] the ID3v2 tag
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(tag)
17
+ popm_frames = tag.frame_list 'POPM'
18
+ return if popm_frames.empty?
19
+
20
+ popm_frames.each do |frame|
21
+ star_rating = POPM_VALUE_TO_STAR_RATING[frame.rating]
22
+ star_rating ||= RATE_VALUE_TO_STAR_RATING[frame.rating]
23
+ return star_rating if star_rating
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for M4A files.
5
+ module M4A
6
+ # Get an M4A file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/MP4/File
10
+ #
11
+ # @param path [String] the M4A file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::MP4::File.open(path) do |file|
18
+ next unless file&.valid? && file&.mp4_tag?
19
+
20
+ items = file.tag.item_map
21
+
22
+ if items.contains 'rate' # MusicBee & MediaMonkey sets this
23
+ rate_value = get_item_value(items.fetch('rate'))
24
+ return RATE_VALUE_TO_STAR_RATING[rate_value]
25
+ end
26
+
27
+ itunes_item = get_itunes_rating_item(items)
28
+ get_item_value(itunes_item) if itunes_item
29
+ end
30
+ end
31
+
32
+ # Gets the value from an MP4 Item.
33
+ #
34
+ # Uses taglib-ruby class:
35
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/MP4/Item
36
+ #
37
+ # @param item [TagLib::MP4::Item] the MP4 item
38
+ # @return [Integer] the item value
39
+ def self.get_item_value(item)
40
+ item.to_string_list.first.to_i
41
+ end
42
+ private_class_method :get_item_value
43
+
44
+ # Gets the iTunes rating MP4 Item from an MP4 ItemMap, if present.
45
+ #
46
+ # Uses taglib-ruby class:
47
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/MP4/ItemMap
48
+ #
49
+ # @param item_map [TagLib::MP4::ItemMap] the MP4 ItemMap
50
+ #
51
+ # @return [TagLib::MP4::Item] the MP4 Item
52
+ # @return [nil] if a rating item is not present
53
+ def self.get_itunes_rating_item(item_map)
54
+ key_a = '----:com.apple.iTunes:Rating' # foobar2000 sets this
55
+ return item_map.fetch(key_a) if item_map.contains key_a
56
+
57
+ key_b = '----:com.apple.iTunes:rating' # Unsure of source
58
+ return item_map.fetch(key_b) if item_map.contains key_b
59
+
60
+ key_c = '----:com.apple.iTunes:RATING' # Unsure of source
61
+ item_map.fetch(key_c) if item_map.contains key_c
62
+ end
63
+ private_class_method :get_itunes_rating_item
64
+ end
65
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for MP3 files.
5
+ module MP3
6
+ # Get an MP3 file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/MPEG/File
10
+ #
11
+ # @param path [String] the MP3 file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::MPEG::File.open(path) do |file|
18
+ next unless file&.valid? && file&.id3v2_tag?
19
+
20
+ AudioRating::ID3v2.get file.id3v2_tag
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for Ogg files.
5
+ module Ogg
6
+ # Get an Ogg file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/Ogg/Vorbis/File
10
+ #
11
+ # @param path [String] the Ogg file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::Ogg::Vorbis::File.open(path) do |file|
18
+ next unless file&.valid?
19
+
20
+ fields = file.tag.field_list_map
21
+ next unless fields.key? 'RATING'
22
+
23
+ rating = fields['RATING'].first.to_i
24
+ return rating if rating <= 5 # foobar2000 sets <= 5
25
+
26
+ # MusicBee & MediaMonkey sets > 5
27
+ RATE_VALUE_TO_STAR_RATING[rating] if rating > 5
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # The library version
5
+ VERSION = '0.1.0'
6
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AudioRating
4
+ # Base class for WAV files.
5
+ module WAV
6
+ # Get an WAV file's embedded star-rating metadata if present.
7
+ #
8
+ # Uses taglib-ruby class:
9
+ # https://rubydoc.info/gems/taglib-ruby/TagLib/RIFF/WAV/File
10
+ #
11
+ # @param path [String] the WAV file path
12
+ #
13
+ # @return [Integer] the star-rating of 1, 2, 3, 4 or 5
14
+ # @return [Float] the star-rating of 0.5, 1.5, 2.5, 3.5 or 4.5
15
+ # @return [nil] if file not found, or file has no star-rating metadata
16
+ def self.get(path)
17
+ TagLib::RIFF::WAV::File.open(path) do |file|
18
+ next unless file&.id3v2_tag?
19
+
20
+ AudioRating::ID3v2.get file.id3v2_tag
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'taglib'
4
+
5
+ require_relative 'audio_rating/aiff'
6
+ require_relative 'audio_rating/base'
7
+ require_relative 'audio_rating/constants'
8
+ require_relative 'audio_rating/flac'
9
+ require_relative 'audio_rating/id3v2'
10
+ require_relative 'audio_rating/m4a'
11
+ require_relative 'audio_rating/mp3'
12
+ require_relative 'audio_rating/ogg'
13
+ require_relative 'audio_rating/version'
14
+ require_relative 'audio_rating/wav'
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: audio_rating
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hayden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: taglib-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ description: |
28
+ Library for reading embedded star-ratings in audio files.
29
+
30
+ Supports file formats: AIFF, FLAC, M4A, MP3, Ogg and WAV.
31
+
32
+ Uses library TagLib and Ruby interface taglib-ruby.
33
+ email:
34
+ - 747644-haayden@users.noreply.gitlab.com
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - ".yardopts"
40
+ - CHANGELOG.md
41
+ - LICENSE
42
+ - README.md
43
+ - lib/audio_rating.rb
44
+ - lib/audio_rating/aiff.rb
45
+ - lib/audio_rating/base.rb
46
+ - lib/audio_rating/constants.rb
47
+ - lib/audio_rating/flac.rb
48
+ - lib/audio_rating/id3v2.rb
49
+ - lib/audio_rating/m4a.rb
50
+ - lib/audio_rating/mp3.rb
51
+ - lib/audio_rating/ogg.rb
52
+ - lib/audio_rating/version.rb
53
+ - lib/audio_rating/wav.rb
54
+ homepage: https://rubygems.org/gems/audio_rating
55
+ licenses:
56
+ - MIT
57
+ metadata:
58
+ homepage_uri: https://rubygems.org/gems/audio_rating
59
+ source_code_uri: https://gitlab.com/haayden/audio_rating
60
+ changelog_uri: https://gitlab.com/haayden/audio_rating/-/blob/main/CHANGELOG.md
61
+ rubygems_mfa_required: 'true'
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '3.0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements:
77
+ - taglib 1.11.1 or higher
78
+ rubygems_version: 3.4.10
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Embedded star-rating audio file reader
82
+ test_files: []