id3taginator 0.8
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 +13 -0
- data/.idea/.gitignore +8 -0
- data/.idea/ID3Taginator.iml +73 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.rspec +3 -0
- data/.rubocop.yml +26 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +408 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/id3taginator.gemspec +37 -0
- data/lib/id3taginator/audio_file.rb +136 -0
- data/lib/id3taginator/errors/id3_tag_error.rb +12 -0
- data/lib/id3taginator/extensions/argument_check.rb +88 -0
- data/lib/id3taginator/extensions/comparable.rb +28 -0
- data/lib/id3taginator/extensions/encodable.rb +215 -0
- data/lib/id3taginator/extensions/optionable.rb +73 -0
- data/lib/id3taginator/frames/buffer/entities/buffer.rb +26 -0
- data/lib/id3taginator/frames/buffer/rbuf_recommended_buffer_size_frame.rb +59 -0
- data/lib/id3taginator/frames/buffer_frames.rb +32 -0
- data/lib/id3taginator/frames/comment/comm_comment_frame.rb +56 -0
- data/lib/id3taginator/frames/comment/entities/comment.rb +26 -0
- data/lib/id3taginator/frames/comment_frames.rb +42 -0
- data/lib/id3taginator/frames/count/entities/popularimeter.rb +26 -0
- data/lib/id3taginator/frames/count/pcnt_play_counter_frame.rb +40 -0
- data/lib/id3taginator/frames/count/popm_popularimeter_frame.rb +52 -0
- data/lib/id3taginator/frames/count_frames.rb +51 -0
- data/lib/id3taginator/frames/custom_frame.rb +39 -0
- data/lib/id3taginator/frames/custom_frames.rb +54 -0
- data/lib/id3taginator/frames/encryption/aenc_audio_encryption.rb +54 -0
- data/lib/id3taginator/frames/encryption/encr_encryption_method_frame.rb +49 -0
- data/lib/id3taginator/frames/encryption/entities/audio_encryption.rb +28 -0
- data/lib/id3taginator/frames/encryption/entities/encryption_method.rb +26 -0
- data/lib/id3taginator/frames/encryption_frames.rb +77 -0
- data/lib/id3taginator/frames/frameable.rb +75 -0
- data/lib/id3taginator/frames/geo/entities/encapsulated_object.rb +28 -0
- data/lib/id3taginator/frames/geo/geob_general_encapsulated_object_frame.rb +59 -0
- data/lib/id3taginator/frames/geo_frames.rb +41 -0
- data/lib/id3taginator/frames/grouping/entities/group_identification.rb +26 -0
- data/lib/id3taginator/frames/grouping/grid_group_identification_frame.rb +49 -0
- data/lib/id3taginator/frames/grouping/grp1_grouping_frame.rb +40 -0
- data/lib/id3taginator/frames/grouping_frames.rb +61 -0
- data/lib/id3taginator/frames/has_id.rb +51 -0
- data/lib/id3taginator/frames/id3v23_frame_flags.rb +64 -0
- data/lib/id3taginator/frames/id3v24_frame_flags.rb +80 -0
- data/lib/id3taginator/frames/id3v2_frame.rb +249 -0
- data/lib/id3taginator/frames/id3v2_frame_factory.rb +98 -0
- data/lib/id3taginator/frames/ipl/entities/involved_person.rb +24 -0
- data/lib/id3taginator/frames/ipl/ipls_involved_people_frame.rb +48 -0
- data/lib/id3taginator/frames/ipl_frames.rb +31 -0
- data/lib/id3taginator/frames/lyrics/entities/unsync_lyrics.rb +26 -0
- data/lib/id3taginator/frames/lyrics/uslt_unsync_lyrics_frame.rb +56 -0
- data/lib/id3taginator/frames/lyrics_frames.rb +42 -0
- data/lib/id3taginator/frames/mcdi/mcdi_music_cd_identifier_frame.rb +40 -0
- data/lib/id3taginator/frames/mcdi_frames.rb +28 -0
- data/lib/id3taginator/frames/picture/apic_picture_frame.rb +106 -0
- data/lib/id3taginator/frames/picture/entities/picture.rb +32 -0
- data/lib/id3taginator/frames/picture_frames.rb +51 -0
- data/lib/id3taginator/frames/private/entities/private_frame.rb +24 -0
- data/lib/id3taginator/frames/private/priv_private_frame.rb +45 -0
- data/lib/id3taginator/frames/private_frames.rb +40 -0
- data/lib/id3taginator/frames/text/entities/copyright.rb +24 -0
- data/lib/id3taginator/frames/text/entities/date.rb +24 -0
- data/lib/id3taginator/frames/text/entities/part_of_set.rb +24 -0
- data/lib/id3taginator/frames/text/entities/time.rb +24 -0
- data/lib/id3taginator/frames/text/entities/track_number.rb +24 -0
- data/lib/id3taginator/frames/text/entities/user_info.rb +24 -0
- data/lib/id3taginator/frames/text/talb_album_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tbpm_bpm_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tcom_composer_frame.rb +42 -0
- data/lib/id3taginator/frames/text/tcon_genre_frame.rb +104 -0
- data/lib/id3taginator/frames/text/tcop_copyright_frame.rb +55 -0
- data/lib/id3taginator/frames/text/tdat_date_frame.rb +60 -0
- data/lib/id3taginator/frames/text/tdly_playlist_delay_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tenc_encoded_by_frame.rb +40 -0
- data/lib/id3taginator/frames/text/text_writers_frame.rb +43 -0
- data/lib/id3taginator/frames/text/tflt_file_type_frame.rb +71 -0
- data/lib/id3taginator/frames/text/time_time_frame.rb +60 -0
- data/lib/id3taginator/frames/text/tit1_content_group_description_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tit2_title_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tit3_subtitle_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tkey_initial_key_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tlan_language_frame.rb +48 -0
- data/lib/id3taginator/frames/text/tlen_length_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tmed_media_type_frame.rb +40 -0
- data/lib/id3taginator/frames/text/toal_original_album_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tofn_original_filename_frame.rb +40 -0
- data/lib/id3taginator/frames/text/toly_original_writers_frame.rb +43 -0
- data/lib/id3taginator/frames/text/tope_original_artists_frame.rb +43 -0
- data/lib/id3taginator/frames/text/tory_original_release_year_frame.rb +42 -0
- data/lib/id3taginator/frames/text/town_file_owner_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tpe1_artist_frame.rb +43 -0
- data/lib/id3taginator/frames/text/tpe2_album_artist_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tpe3_conductor_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tpe4_modified_by_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tpos_part_of_set_frame.rb +50 -0
- data/lib/id3taginator/frames/text/tpub_publisher_frame.rb +40 -0
- data/lib/id3taginator/frames/text/trck_track_number_frame.rb +50 -0
- data/lib/id3taginator/frames/text/trda_recording_dates_frame.rb +42 -0
- data/lib/id3taginator/frames/text/trsn_internet_radio_station_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tsiz_size_frame.rb +41 -0
- data/lib/id3taginator/frames/text/tsoa_album_sort_order_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tsop_performer_sort_order_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tsot_title_sort_order_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tsrc_isrc_frame.rb +40 -0
- data/lib/id3taginator/frames/text/tsse_encoder_frame.rb +40 -0
- data/lib/id3taginator/frames/text/txxx_user_text_info_frame.rb +51 -0
- data/lib/id3taginator/frames/text/tyer_year_frame.rb +42 -0
- data/lib/id3taginator/frames/text_frames.rb +840 -0
- data/lib/id3taginator/frames/tos/entities/ownership.rb +26 -0
- data/lib/id3taginator/frames/tos/entities/terms_of_use.rb +24 -0
- data/lib/id3taginator/frames/tos/owne_ownership_frame.rb +53 -0
- data/lib/id3taginator/frames/tos/user_terms_of_use_frame.rb +49 -0
- data/lib/id3taginator/frames/tos_frames.rb +54 -0
- data/lib/id3taginator/frames/ufid/entities/ufid_info.rb +24 -0
- data/lib/id3taginator/frames/ufid/ufid_unique_file_identifier_frame.rb +47 -0
- data/lib/id3taginator/frames/ufid_frames.rb +40 -0
- data/lib/id3taginator/frames/url/entities/user_info.rb +24 -0
- data/lib/id3taginator/frames/url/wcom_commercial_url_frame.rb +40 -0
- data/lib/id3taginator/frames/url/wcop_copyright_url_frame.rb +40 -0
- data/lib/id3taginator/frames/url/woaf_official_file_webpage_frame.rb +40 -0
- data/lib/id3taginator/frames/url/woar_official_artist_webpage_frame.rb +40 -0
- data/lib/id3taginator/frames/url/woas_official_source_webpage_frame.rb +40 -0
- data/lib/id3taginator/frames/url/wors_official_radio_station_homepage_frame.rb +40 -0
- data/lib/id3taginator/frames/url/wpay_payment_url_frame.rb +40 -0
- data/lib/id3taginator/frames/url/wpub_official_publisher_webpage_frame.rb +40 -0
- data/lib/id3taginator/frames/url/wxxx_user_url_link_frame.rb +50 -0
- data/lib/id3taginator/frames/url_frames.rb +195 -0
- data/lib/id3taginator/genres.rb +168 -0
- data/lib/id3taginator/header/id3v23_extended_header.rb +37 -0
- data/lib/id3taginator/header/id3v24_extended_header.rb +100 -0
- data/lib/id3taginator/header/id3v2_flags.rb +64 -0
- data/lib/id3taginator/id3v1_tag.rb +156 -0
- data/lib/id3taginator/id3v22_tag.rb +30 -0
- data/lib/id3taginator/id3v23_tag.rb +63 -0
- data/lib/id3taginator/id3v24_tag.rb +75 -0
- data/lib/id3taginator/id3v2_tag.rb +241 -0
- data/lib/id3taginator/options/options.rb +33 -0
- data/lib/id3taginator/util/compress_util.rb +25 -0
- data/lib/id3taginator/util/math_util.rb +68 -0
- data/lib/id3taginator/util/sync_util.rb +65 -0
- data/lib/id3taginator.rb +449 -0
- metadata +198 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Frames
|
|
5
|
+
module Url
|
|
6
|
+
class UserUrlLinkFrame < Id3v2Frame
|
|
7
|
+
include HasId
|
|
8
|
+
|
|
9
|
+
frame_info :WXX, :WXXX, :WXXX
|
|
10
|
+
|
|
11
|
+
attr_accessor :description, :url
|
|
12
|
+
|
|
13
|
+
# builds the custom user url link frame
|
|
14
|
+
#
|
|
15
|
+
# @param description [String] the description
|
|
16
|
+
# @param url [String] the url
|
|
17
|
+
# @param options [Options::Options] options to use
|
|
18
|
+
# @param id3_version [Integer] the id3 version to build the frame for
|
|
19
|
+
#
|
|
20
|
+
# @return [Id3v2Frame] the resulting id3v2 frame
|
|
21
|
+
def self.build_frame(description, url, options = nil, id3_version: 3)
|
|
22
|
+
supported?('WXXX', id3_version, options)
|
|
23
|
+
|
|
24
|
+
argument_not_nil(description, 'description')
|
|
25
|
+
argument_not_nil(url, 'url')
|
|
26
|
+
|
|
27
|
+
frame = new(frame_id(id3_version, options), 0, build_id3_flags(id3_version), '')
|
|
28
|
+
frame.description = description
|
|
29
|
+
frame.url = url
|
|
30
|
+
frame
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def process_content(content)
|
|
34
|
+
content_io = StringIO.new(content)
|
|
35
|
+
encoding_byte = content_io.getbyte
|
|
36
|
+
encoding = find_encoding(encoding_byte)
|
|
37
|
+
|
|
38
|
+
encoded_description = read_stream_until(content_io, zero_byte(encoding))
|
|
39
|
+
@description = decode(encoded_description, encoding)
|
|
40
|
+
@url = content_io.read
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def content_to_bytes
|
|
44
|
+
encoded_description = encode(@description, null_terminated: true)
|
|
45
|
+
merge(default_encoding_destination_byte, encoded_description, @url)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Frames
|
|
5
|
+
module UrlFrames
|
|
6
|
+
include Frames::Frameable
|
|
7
|
+
|
|
8
|
+
# extracts the commercial information url (WCOM/WCM)
|
|
9
|
+
#
|
|
10
|
+
# @return [String, nil] returns the URL
|
|
11
|
+
def commercial_information_url
|
|
12
|
+
find_frame(Url::CommercialUrlFrame.frame_id(@major_version, @options))&.url
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# sets the commercial information url (WCOM/WCM)
|
|
16
|
+
#
|
|
17
|
+
# @param url [String] the url
|
|
18
|
+
def commercial_information_url=(url)
|
|
19
|
+
set_frame_fields(Url::CommercialUrlFrame, [:@url], url)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# removes the commercial information url frame
|
|
23
|
+
def remove_commercial_information_url
|
|
24
|
+
@frames.delete_if { |f| f.frame_id == Url::CommercialUrlFrame.frame_id(@major_version, @options) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# extracts the copyright information url (WCOP/WCP)
|
|
28
|
+
#
|
|
29
|
+
# @return [String, nil] returns the URL
|
|
30
|
+
def copyright_information_url
|
|
31
|
+
find_frame(Url::CopyrightUrlFrame.frame_id(@major_version, @options))&.url
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# sets the copyright information url (WCOP/WCP)
|
|
35
|
+
#
|
|
36
|
+
# @param url [String] the url
|
|
37
|
+
def copyright_information_url=(url)
|
|
38
|
+
set_frame_fields(Url::CopyrightUrlFrame, [:@url], url)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# removes the copyright information url frame
|
|
42
|
+
def remove_copyright_information_url
|
|
43
|
+
@frames.delete_if { |f| f.frame_id == Url::CopyrightUrlFrame.frame_id(@major_version, @options) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# extracts the official audio file url (WOAF/WAF)
|
|
47
|
+
#
|
|
48
|
+
# @return [String, nil] returns the URL
|
|
49
|
+
def official_audio_file_url
|
|
50
|
+
find_frame(Url::OfficialFileWebpageFrame.frame_id(@major_version, @options))&.url
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# sets the official audio file url (WOAF/WAF)
|
|
54
|
+
#
|
|
55
|
+
# @param url [String] the url
|
|
56
|
+
def official_audio_file_url=(url)
|
|
57
|
+
set_frame_fields(Url::OfficialFileWebpageFrame, [:@url], url)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# removes the official audio file url frame
|
|
61
|
+
def remove_official_audio_file_url
|
|
62
|
+
@frames.delete_if { |f| f.frame_id == Url::OfficialFileWebpageFrame.frame_id(@major_version, @options) }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# extracts the official artist url (WOAR/WAR)
|
|
66
|
+
#
|
|
67
|
+
# @return [String, nil] returns the URL
|
|
68
|
+
def official_artist_url
|
|
69
|
+
find_frame(Url::OfficialArtistWebpageFrame.frame_id(@major_version, @options))&.url
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# sets the official artist url (WOAR/WAR)
|
|
73
|
+
#
|
|
74
|
+
# @param url [String] the url
|
|
75
|
+
def official_artist_url=(url)
|
|
76
|
+
set_frame_fields(Url::OfficialArtistWebpageFrame, [:@url], url)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# removes the official artist url frame
|
|
80
|
+
def remove_official_artist_url
|
|
81
|
+
@frames.delete_if { |f| f.frame_id == Url::OfficialArtistWebpageFrame.frame_id(@major_version, @options) }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# extracts the official source url (WOAS/WAS)
|
|
85
|
+
#
|
|
86
|
+
# @return [String, nil] returns the URL
|
|
87
|
+
def official_source_url
|
|
88
|
+
find_frame(Url::OfficialSourceWebpageFrame.frame_id(@major_version, @options))&.url
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# sets the official source url (WOAS/WAS)
|
|
92
|
+
#
|
|
93
|
+
# @param url [String] the url
|
|
94
|
+
def official_source_url=(url)
|
|
95
|
+
set_frame_fields(Url::OfficialSourceWebpageFrame, [:@url], url)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# removes the official source url frame
|
|
99
|
+
def remove_official_source_url
|
|
100
|
+
@frames.delete_if { |f| f.frame_id == Url::OfficialSourceWebpageFrame.frame_id(@major_version, @options) }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# extracts the official radio station url (WORS)
|
|
104
|
+
#
|
|
105
|
+
# @return [String, nil] returns the URL
|
|
106
|
+
def official_radio_station_homepage
|
|
107
|
+
find_frame(Url::OfficialAudioRadioStationHomepageFrame.frame_id(@major_version, @options))&.url
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# sets the official radio station url (WORS)
|
|
111
|
+
#
|
|
112
|
+
# @param url [String] the url
|
|
113
|
+
def official_radio_station_homepage=(url)
|
|
114
|
+
set_frame_fields(Url::OfficialAudioRadioStationHomepageFrame, [:@url], url)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# removes the official radio station homepage frame
|
|
118
|
+
def remove_official_radio_station_homepage
|
|
119
|
+
@frames.delete_if do |f|
|
|
120
|
+
f.frame_id == Url::OfficialAudioRadioStationHomepageFrame.frame_id(@major_version, @options)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# extracts the official radio station url (WPAY)
|
|
125
|
+
#
|
|
126
|
+
# @return [String, nil] returns the URL
|
|
127
|
+
def payment_url
|
|
128
|
+
find_frame(Url::PaymentUrlFrame.frame_id(@major_version, @options))&.url
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# sets the payment url (WPAY)
|
|
132
|
+
#
|
|
133
|
+
# @param url [String] the url
|
|
134
|
+
def payment_url=(url)
|
|
135
|
+
set_frame_fields(Url::PaymentUrlFrame, [:@url], url)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# removes the payment frame
|
|
139
|
+
def remove_payment_url
|
|
140
|
+
@frames.delete_if { |f| f.frame_id == Url::PaymentUrlFrame.frame_id(@major_version, @options) }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# extracts the official publisher url (WPUB/WPB)
|
|
144
|
+
#
|
|
145
|
+
# @return [String, nil] returns the URL
|
|
146
|
+
def official_publisher_webpage
|
|
147
|
+
find_frame(Url::OfficialPublisherWebpageFrame.frame_id(@major_version, @options))&.url
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# sets the official publisher url (WPUB/WPB)
|
|
151
|
+
#
|
|
152
|
+
# @param url [String] the url
|
|
153
|
+
def official_publisher_webpage=(url)
|
|
154
|
+
set_frame_fields(Url::OfficialPublisherWebpageFrame, [:@url], url)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# removes the official publisher webpage frame
|
|
158
|
+
def remove_official_publisher_webpage
|
|
159
|
+
@frames.delete_if { |f| f.frame_id == Url::OfficialPublisherWebpageFrame.frame_id(@major_version, @options) }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# extracts the user custom url links (WXXX/WXX)
|
|
163
|
+
#
|
|
164
|
+
# @return [Array<Frames::Url::Entities::UserInfo>] returns the custom URL links
|
|
165
|
+
def user_custom_url_links
|
|
166
|
+
frame = find_frames(Url::UserUrlLinkFrame.frame_id(@major_version, @options))
|
|
167
|
+
return [] if frame.nil? || frame.empty?
|
|
168
|
+
|
|
169
|
+
frame.map { |f| Url::Entities::UserInfo.new(f.description, f.url) }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# adds a user custom url link (WXXX/WXX)
|
|
173
|
+
# Multiple ones can be added, as long as they have different description
|
|
174
|
+
#
|
|
175
|
+
# @param custom_url [Frames::Url::Entities::UserInfo] the custom url link to add
|
|
176
|
+
def user_custom_url_link=(custom_url)
|
|
177
|
+
set_frame_fields_by_selector(Url::UserUrlLinkFrame, %i[@description @url],
|
|
178
|
+
->(f) { f.description == custom_url.description },
|
|
179
|
+
custom_url.description, custom_url.url)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
alias add_user_custom_url_link user_custom_url_link=
|
|
183
|
+
|
|
184
|
+
# removes a user custom url link for the specific description (WXXX/WXX)
|
|
185
|
+
#
|
|
186
|
+
# @param description [String] the description
|
|
187
|
+
def remove_user_custom_url_link(description)
|
|
188
|
+
@frames.delete_if do |f|
|
|
189
|
+
f.frame_id == Url::UserUrlLinkFrame.frame_id(@major_version, @options) &&
|
|
190
|
+
f.description == description
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Genres
|
|
5
|
+
BLUES = 0
|
|
6
|
+
CLASSIC_ROCK = 1
|
|
7
|
+
COUNTRY = 2
|
|
8
|
+
DANCE = 3
|
|
9
|
+
DISCO = 4
|
|
10
|
+
FUNK = 5
|
|
11
|
+
GRUNGE = 6
|
|
12
|
+
HIP_HOP = 7
|
|
13
|
+
JAZZ = 8
|
|
14
|
+
METAL = 9
|
|
15
|
+
NEW_AGE = 10
|
|
16
|
+
OLDIES = 11
|
|
17
|
+
OTHER = 12
|
|
18
|
+
POP = 13
|
|
19
|
+
RNB = 14
|
|
20
|
+
RAP = 15
|
|
21
|
+
REGGAE = 16
|
|
22
|
+
ROCK = 17
|
|
23
|
+
TECHNO = 18
|
|
24
|
+
INDUSTRIAL = 19
|
|
25
|
+
ALTERNATIVE = 20
|
|
26
|
+
SKA = 21
|
|
27
|
+
DEATH_METAL = 22
|
|
28
|
+
PRANKS = 23
|
|
29
|
+
SOUNDTRACK = 24
|
|
30
|
+
EURO_TECHNO = 25
|
|
31
|
+
AMBIENT = 26
|
|
32
|
+
TRIP_HOP = 27
|
|
33
|
+
VOCAL = 28
|
|
34
|
+
JAZZ_FUNK = 29
|
|
35
|
+
FUSION = 30
|
|
36
|
+
TRANCE = 31
|
|
37
|
+
CLASSICAL = 32
|
|
38
|
+
INSTRUMENTAL = 33
|
|
39
|
+
ACID = 34
|
|
40
|
+
HOUSE = 35
|
|
41
|
+
GAME = 36
|
|
42
|
+
SOUND_CLIP = 37
|
|
43
|
+
GOSPEL = 38
|
|
44
|
+
NOISE = 39
|
|
45
|
+
ALT_ROCK = 40
|
|
46
|
+
BASS = 41
|
|
47
|
+
SOUL = 42
|
|
48
|
+
PUNK = 43
|
|
49
|
+
SPACE = 44
|
|
50
|
+
MEDITATIVE = 45
|
|
51
|
+
INSTRUMENTAL_POP = 46
|
|
52
|
+
INSTRUMENTAL_ROCK = 47
|
|
53
|
+
ETHNIC = 48
|
|
54
|
+
GOTHIC = 49
|
|
55
|
+
DARKWAVE = 50
|
|
56
|
+
TECHNO_INDUSTRIAL = 51
|
|
57
|
+
ELECTRONIC = 52
|
|
58
|
+
POP_FOLK = 53
|
|
59
|
+
EURODANCE = 54
|
|
60
|
+
DREAM = 55
|
|
61
|
+
SOUTHERN_ROCK = 56
|
|
62
|
+
COMEDY = 57
|
|
63
|
+
CULT = 58
|
|
64
|
+
GANGSTA = 59
|
|
65
|
+
TOP_40 = 60
|
|
66
|
+
CHRISTIAN_RAP = 61
|
|
67
|
+
POP_FUNK = 62
|
|
68
|
+
JUNGLE = 63
|
|
69
|
+
NATIVE_AMERICAN = 64
|
|
70
|
+
CABARET = 65
|
|
71
|
+
NEW_WAVE = 66
|
|
72
|
+
PSYCHEDELIC = 67
|
|
73
|
+
RAVE = 68
|
|
74
|
+
SHOWTUNES = 69
|
|
75
|
+
TRAILER = 70
|
|
76
|
+
LO_FI = 71
|
|
77
|
+
TRIBAL = 72
|
|
78
|
+
ACID_PUNK = 73
|
|
79
|
+
ACID_JAZZ = 74
|
|
80
|
+
POLKA = 75
|
|
81
|
+
RETRO = 76
|
|
82
|
+
MUSICAL = 77
|
|
83
|
+
ROCK_N_ROLL = 78
|
|
84
|
+
HARD_ROCK = 79
|
|
85
|
+
FOLK = 80
|
|
86
|
+
FOLK_ROCK = 81
|
|
87
|
+
NATIONAL_FOLK = 82
|
|
88
|
+
SWING = 83
|
|
89
|
+
FAST_FUSION = 84
|
|
90
|
+
BEBOB = 85
|
|
91
|
+
LATIN = 86
|
|
92
|
+
REVIVAL = 87
|
|
93
|
+
CELTIC = 88
|
|
94
|
+
BLUEGRASS = 89
|
|
95
|
+
AVANTGARDE = 90
|
|
96
|
+
GOTHIC_ROCK = 91
|
|
97
|
+
PROGRESSIVE_ROCK = 92
|
|
98
|
+
PSYCHEDELIC_ROCK = 93
|
|
99
|
+
SYMPHONIC_ROCK = 94
|
|
100
|
+
SLOW_ROCK = 95
|
|
101
|
+
BIG_BAND = 96
|
|
102
|
+
CHORUS = 97
|
|
103
|
+
EASY_LISTENING = 98
|
|
104
|
+
ACOUSTIC = 99
|
|
105
|
+
HUMOUR = 100
|
|
106
|
+
SPEECH = 101
|
|
107
|
+
CHANSON = 102
|
|
108
|
+
OPERA = 103
|
|
109
|
+
CHAMBER_MUSIC = 104
|
|
110
|
+
SONATA = 105
|
|
111
|
+
SYMPHONY = 106
|
|
112
|
+
BOOTY_BASS = 107
|
|
113
|
+
PRIMUS = 108
|
|
114
|
+
PORN_GROOVE = 109
|
|
115
|
+
SATIRE_PARODY = 110
|
|
116
|
+
SLOW_JAM = 111
|
|
117
|
+
CLUB = 112
|
|
118
|
+
TANGO = 113
|
|
119
|
+
SAMBA = 114
|
|
120
|
+
FOLKLORE = 115
|
|
121
|
+
BALLAD = 116
|
|
122
|
+
POWER_BALLAD = 117
|
|
123
|
+
RHYTHMIC_SOUL = 118
|
|
124
|
+
FREESTYLE = 119
|
|
125
|
+
DUET = 120
|
|
126
|
+
PUNK_ROCK = 121
|
|
127
|
+
DRUM_SOLO = 122
|
|
128
|
+
ACAPELLA = 123
|
|
129
|
+
EURO_HOUSE = 124
|
|
130
|
+
DANCE_HALL = 125
|
|
131
|
+
GOA = 126
|
|
132
|
+
DRUM_N_BASS = 127
|
|
133
|
+
CLUB_HOUSE = 128
|
|
134
|
+
HARDCORE = 129
|
|
135
|
+
TERROR = 130
|
|
136
|
+
INDIE = 131
|
|
137
|
+
BRITPOP = 132
|
|
138
|
+
NEGERPUNK = 133
|
|
139
|
+
POLSK_PUNK = 134
|
|
140
|
+
BEAT = 135
|
|
141
|
+
CHRISTIAN_GANGSTA = 136
|
|
142
|
+
HEAVY_METAL = 137
|
|
143
|
+
THRASH_METAL = 138
|
|
144
|
+
ANIME = 139
|
|
145
|
+
JPOP = 140
|
|
146
|
+
SYNTHPOP = 141
|
|
147
|
+
INVALID = 255
|
|
148
|
+
|
|
149
|
+
def self.genre(id)
|
|
150
|
+
return nil if id.nil?
|
|
151
|
+
|
|
152
|
+
result = constants.find { |genre| const_get(genre) == id }
|
|
153
|
+
return :INVALID if result.nil?
|
|
154
|
+
|
|
155
|
+
result
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def self.genre_by_name(name)
|
|
159
|
+
return INVALID if name.nil?
|
|
160
|
+
|
|
161
|
+
begin
|
|
162
|
+
const_get(name)
|
|
163
|
+
rescue NameError
|
|
164
|
+
name
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Header
|
|
5
|
+
class Id3v23ExtendedHeader
|
|
6
|
+
|
|
7
|
+
attr_accessor :size, :flags, :padding, :crc_data
|
|
8
|
+
|
|
9
|
+
# constructor
|
|
10
|
+
#
|
|
11
|
+
# @param size [Integer] the size of the extended header
|
|
12
|
+
# @param flags [String] 2 byte Array as a String representing the flags
|
|
13
|
+
# @param padding [Integer] the number of padding of the extended header
|
|
14
|
+
# @param crc_data [String] the crc data if present
|
|
15
|
+
def initialize(size, flags, padding, crc_data = nil)
|
|
16
|
+
@size = size
|
|
17
|
+
@flags = flags
|
|
18
|
+
@padding = padding
|
|
19
|
+
@crc_data = crc_data
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# returns the CRC data if present
|
|
23
|
+
#
|
|
24
|
+
# @return [String, nil] the CRC data
|
|
25
|
+
def crc
|
|
26
|
+
@crc_data
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# determined if the crc is present
|
|
30
|
+
#
|
|
31
|
+
# @return [Boolean] true if crc is present, else false
|
|
32
|
+
def crc?
|
|
33
|
+
(@flags[0] & 0b10000000) == 0b10000000
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Header
|
|
5
|
+
class Id3v24ExtendedHeader
|
|
6
|
+
|
|
7
|
+
attr_accessor :size, :flags
|
|
8
|
+
|
|
9
|
+
# constructor
|
|
10
|
+
#
|
|
11
|
+
# @param size [Integer] the size of the extended header
|
|
12
|
+
# @param flags [String] 2 byte Array as a String representing the flags
|
|
13
|
+
def initialize(size, flags)
|
|
14
|
+
@size = size
|
|
15
|
+
@flags = flags
|
|
16
|
+
@tag_is_update = false
|
|
17
|
+
@crc_data = nil
|
|
18
|
+
@restrictions = 0b00000000
|
|
19
|
+
|
|
20
|
+
flags_stream = StringIO.new(flags)
|
|
21
|
+
ext_flag = flags_stream.readbyte
|
|
22
|
+
# tag is update
|
|
23
|
+
if bit_set?(ext_flag, 0b01000000)
|
|
24
|
+
@tag_is_update = true
|
|
25
|
+
flags_stream.readbyte
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# crc data
|
|
29
|
+
if bit_set?(ext_flag, 0b00100000)
|
|
30
|
+
length = ext_flag.readbyte
|
|
31
|
+
@crc_data = flags_stream.read(length)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
ext_flag.readbyte if bit_set?(ext_flag, 0b00010000)
|
|
35
|
+
@restrictions = ext_flag.readbyte if bit_set?(ext_flag, 0b00010000)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# determined if the tag is an update
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean] true if it is an update, else false
|
|
41
|
+
def tag_is_an_update?
|
|
42
|
+
@tag_is_update
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# returns the CRC data if present
|
|
46
|
+
#
|
|
47
|
+
# @return [String, nil] the CRC data
|
|
48
|
+
def crc
|
|
49
|
+
@crc_data
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# determined if the tag is size restricted
|
|
53
|
+
#
|
|
54
|
+
# @return [Boolean] true if it restricted, else false
|
|
55
|
+
def tag_size_restrictions?
|
|
56
|
+
(@restrictions & 0b11000000) == 0b11000000
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# determined if the tag is text encoding restricted
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean] true if text encoding restricted, else false
|
|
62
|
+
def text_encoding_restrictions?
|
|
63
|
+
(@restrictions & 0b00100000) == 0b00100000
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# determined if the tag is fields size restricted
|
|
67
|
+
#
|
|
68
|
+
# @return [Boolean] true if fields size restricted, else false
|
|
69
|
+
def text_fields_size_restrictions?
|
|
70
|
+
(@restrictions & 0b00011000) == 0b00011000
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# determined if the tag is encoding restricted
|
|
74
|
+
#
|
|
75
|
+
# @return [Boolean] true if encoding restricted, else false
|
|
76
|
+
def image_encoding_restrictions?
|
|
77
|
+
(@restrictions & 0b00000100) == 0b00000100
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# determined if the tag is image encoding restricted
|
|
81
|
+
#
|
|
82
|
+
# @return [Boolean] true if image encoding restricted, else false
|
|
83
|
+
def image_size_restrictions?
|
|
84
|
+
(@restrictions & 0b00000011) == 0b00000011
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# checks if the given bit of the given byte is set
|
|
88
|
+
#
|
|
89
|
+
# @param byte [Integer] the byte to check if a specific bit is set
|
|
90
|
+
# @param set [Byte] the Byte where the bit is set that should be checked
|
|
91
|
+
#
|
|
92
|
+
# @return [Boolean] true if the bit is set, else false
|
|
93
|
+
def bit_set?(byte, set)
|
|
94
|
+
(byte & set) == set
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private :bit_set?
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
module Header
|
|
5
|
+
class Id3v2Flags
|
|
6
|
+
|
|
7
|
+
# constructor
|
|
8
|
+
#
|
|
9
|
+
# @param flags [Integer] the 1 byte header flag
|
|
10
|
+
def initialize(flags)
|
|
11
|
+
@flags = flags
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# determined if the tag is unsynchronized
|
|
15
|
+
#
|
|
16
|
+
# @return [Boolean] true if unsynchronized, else false
|
|
17
|
+
def unsynchronized?
|
|
18
|
+
(@flags & 0b1000_0000) == 0b1000_0000
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# enables or synchronization for the tag
|
|
22
|
+
#
|
|
23
|
+
# @param enabled [Boolean] true, if tag should be synchronized, else false
|
|
24
|
+
def unsynchronized=(enabled)
|
|
25
|
+
@flags = enabled ? @flags | 0b1000_0000 : @flags & 0b0111_1111
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# determines if an extended header is present
|
|
29
|
+
#
|
|
30
|
+
# @return [Boolean] true if header is present, else false
|
|
31
|
+
def extended_header?
|
|
32
|
+
(@flags & 0b0100_0000) == 0b0100_0000
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# determines if experimental tags are present
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean] true if experimental tags present, else false
|
|
38
|
+
def experimental?
|
|
39
|
+
(@flags & 0b0010_0000) == 0b0010_0000
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# determines if a footer is present
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean] true if a footer is present, else false
|
|
45
|
+
def footer?
|
|
46
|
+
(@flags & 0b0001_0000) == 0b0001_0000
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# enables or disables a footer
|
|
50
|
+
#
|
|
51
|
+
# @param enabled [Boolean] true, if the footer should be set to the tag, else false
|
|
52
|
+
def footer=(enabled)
|
|
53
|
+
@flags = enabled ? @flags | 0b0001_0000 : @flags & 0b1110_1111
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# dumps the flags to a byte string
|
|
57
|
+
#
|
|
58
|
+
# @return [String] the String representing the flags
|
|
59
|
+
def to_bytes
|
|
60
|
+
@flags.chr
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|