audio_rating 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []