id3taginator 0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.idea/.gitignore +8 -0
  4. data/.idea/ID3Taginator.iml +73 -0
  5. data/.idea/misc.xml +4 -0
  6. data/.idea/modules.xml +8 -0
  7. data/.idea/vcs.xml +6 -0
  8. data/.rspec +3 -0
  9. data/.rubocop.yml +26 -0
  10. data/CHANGELOG.md +5 -0
  11. data/CODE_OF_CONDUCT.md +84 -0
  12. data/Gemfile +12 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +408 -0
  15. data/Rakefile +12 -0
  16. data/bin/console +15 -0
  17. data/bin/setup +8 -0
  18. data/id3taginator.gemspec +37 -0
  19. data/lib/id3taginator/audio_file.rb +136 -0
  20. data/lib/id3taginator/errors/id3_tag_error.rb +12 -0
  21. data/lib/id3taginator/extensions/argument_check.rb +88 -0
  22. data/lib/id3taginator/extensions/comparable.rb +28 -0
  23. data/lib/id3taginator/extensions/encodable.rb +215 -0
  24. data/lib/id3taginator/extensions/optionable.rb +73 -0
  25. data/lib/id3taginator/frames/buffer/entities/buffer.rb +26 -0
  26. data/lib/id3taginator/frames/buffer/rbuf_recommended_buffer_size_frame.rb +59 -0
  27. data/lib/id3taginator/frames/buffer_frames.rb +32 -0
  28. data/lib/id3taginator/frames/comment/comm_comment_frame.rb +56 -0
  29. data/lib/id3taginator/frames/comment/entities/comment.rb +26 -0
  30. data/lib/id3taginator/frames/comment_frames.rb +42 -0
  31. data/lib/id3taginator/frames/count/entities/popularimeter.rb +26 -0
  32. data/lib/id3taginator/frames/count/pcnt_play_counter_frame.rb +40 -0
  33. data/lib/id3taginator/frames/count/popm_popularimeter_frame.rb +52 -0
  34. data/lib/id3taginator/frames/count_frames.rb +51 -0
  35. data/lib/id3taginator/frames/custom_frame.rb +39 -0
  36. data/lib/id3taginator/frames/custom_frames.rb +54 -0
  37. data/lib/id3taginator/frames/encryption/aenc_audio_encryption.rb +54 -0
  38. data/lib/id3taginator/frames/encryption/encr_encryption_method_frame.rb +49 -0
  39. data/lib/id3taginator/frames/encryption/entities/audio_encryption.rb +28 -0
  40. data/lib/id3taginator/frames/encryption/entities/encryption_method.rb +26 -0
  41. data/lib/id3taginator/frames/encryption_frames.rb +77 -0
  42. data/lib/id3taginator/frames/frameable.rb +75 -0
  43. data/lib/id3taginator/frames/geo/entities/encapsulated_object.rb +28 -0
  44. data/lib/id3taginator/frames/geo/geob_general_encapsulated_object_frame.rb +59 -0
  45. data/lib/id3taginator/frames/geo_frames.rb +41 -0
  46. data/lib/id3taginator/frames/grouping/entities/group_identification.rb +26 -0
  47. data/lib/id3taginator/frames/grouping/grid_group_identification_frame.rb +49 -0
  48. data/lib/id3taginator/frames/grouping/grp1_grouping_frame.rb +40 -0
  49. data/lib/id3taginator/frames/grouping_frames.rb +61 -0
  50. data/lib/id3taginator/frames/has_id.rb +51 -0
  51. data/lib/id3taginator/frames/id3v23_frame_flags.rb +64 -0
  52. data/lib/id3taginator/frames/id3v24_frame_flags.rb +80 -0
  53. data/lib/id3taginator/frames/id3v2_frame.rb +249 -0
  54. data/lib/id3taginator/frames/id3v2_frame_factory.rb +98 -0
  55. data/lib/id3taginator/frames/ipl/entities/involved_person.rb +24 -0
  56. data/lib/id3taginator/frames/ipl/ipls_involved_people_frame.rb +48 -0
  57. data/lib/id3taginator/frames/ipl_frames.rb +31 -0
  58. data/lib/id3taginator/frames/lyrics/entities/unsync_lyrics.rb +26 -0
  59. data/lib/id3taginator/frames/lyrics/uslt_unsync_lyrics_frame.rb +56 -0
  60. data/lib/id3taginator/frames/lyrics_frames.rb +42 -0
  61. data/lib/id3taginator/frames/mcdi/mcdi_music_cd_identifier_frame.rb +40 -0
  62. data/lib/id3taginator/frames/mcdi_frames.rb +28 -0
  63. data/lib/id3taginator/frames/picture/apic_picture_frame.rb +106 -0
  64. data/lib/id3taginator/frames/picture/entities/picture.rb +32 -0
  65. data/lib/id3taginator/frames/picture_frames.rb +51 -0
  66. data/lib/id3taginator/frames/private/entities/private_frame.rb +24 -0
  67. data/lib/id3taginator/frames/private/priv_private_frame.rb +45 -0
  68. data/lib/id3taginator/frames/private_frames.rb +40 -0
  69. data/lib/id3taginator/frames/text/entities/copyright.rb +24 -0
  70. data/lib/id3taginator/frames/text/entities/date.rb +24 -0
  71. data/lib/id3taginator/frames/text/entities/part_of_set.rb +24 -0
  72. data/lib/id3taginator/frames/text/entities/time.rb +24 -0
  73. data/lib/id3taginator/frames/text/entities/track_number.rb +24 -0
  74. data/lib/id3taginator/frames/text/entities/user_info.rb +24 -0
  75. data/lib/id3taginator/frames/text/talb_album_frame.rb +40 -0
  76. data/lib/id3taginator/frames/text/tbpm_bpm_frame.rb +40 -0
  77. data/lib/id3taginator/frames/text/tcom_composer_frame.rb +42 -0
  78. data/lib/id3taginator/frames/text/tcon_genre_frame.rb +104 -0
  79. data/lib/id3taginator/frames/text/tcop_copyright_frame.rb +55 -0
  80. data/lib/id3taginator/frames/text/tdat_date_frame.rb +60 -0
  81. data/lib/id3taginator/frames/text/tdly_playlist_delay_frame.rb +40 -0
  82. data/lib/id3taginator/frames/text/tenc_encoded_by_frame.rb +40 -0
  83. data/lib/id3taginator/frames/text/text_writers_frame.rb +43 -0
  84. data/lib/id3taginator/frames/text/tflt_file_type_frame.rb +71 -0
  85. data/lib/id3taginator/frames/text/time_time_frame.rb +60 -0
  86. data/lib/id3taginator/frames/text/tit1_content_group_description_frame.rb +40 -0
  87. data/lib/id3taginator/frames/text/tit2_title_frame.rb +40 -0
  88. data/lib/id3taginator/frames/text/tit3_subtitle_frame.rb +40 -0
  89. data/lib/id3taginator/frames/text/tkey_initial_key_frame.rb +40 -0
  90. data/lib/id3taginator/frames/text/tlan_language_frame.rb +48 -0
  91. data/lib/id3taginator/frames/text/tlen_length_frame.rb +40 -0
  92. data/lib/id3taginator/frames/text/tmed_media_type_frame.rb +40 -0
  93. data/lib/id3taginator/frames/text/toal_original_album_frame.rb +40 -0
  94. data/lib/id3taginator/frames/text/tofn_original_filename_frame.rb +40 -0
  95. data/lib/id3taginator/frames/text/toly_original_writers_frame.rb +43 -0
  96. data/lib/id3taginator/frames/text/tope_original_artists_frame.rb +43 -0
  97. data/lib/id3taginator/frames/text/tory_original_release_year_frame.rb +42 -0
  98. data/lib/id3taginator/frames/text/town_file_owner_frame.rb +40 -0
  99. data/lib/id3taginator/frames/text/tpe1_artist_frame.rb +43 -0
  100. data/lib/id3taginator/frames/text/tpe2_album_artist_frame.rb +40 -0
  101. data/lib/id3taginator/frames/text/tpe3_conductor_frame.rb +40 -0
  102. data/lib/id3taginator/frames/text/tpe4_modified_by_frame.rb +40 -0
  103. data/lib/id3taginator/frames/text/tpos_part_of_set_frame.rb +50 -0
  104. data/lib/id3taginator/frames/text/tpub_publisher_frame.rb +40 -0
  105. data/lib/id3taginator/frames/text/trck_track_number_frame.rb +50 -0
  106. data/lib/id3taginator/frames/text/trda_recording_dates_frame.rb +42 -0
  107. data/lib/id3taginator/frames/text/trsn_internet_radio_station_frame.rb +40 -0
  108. data/lib/id3taginator/frames/text/tsiz_size_frame.rb +41 -0
  109. data/lib/id3taginator/frames/text/tsoa_album_sort_order_frame.rb +40 -0
  110. data/lib/id3taginator/frames/text/tsop_performer_sort_order_frame.rb +40 -0
  111. data/lib/id3taginator/frames/text/tsot_title_sort_order_frame.rb +40 -0
  112. data/lib/id3taginator/frames/text/tsrc_isrc_frame.rb +40 -0
  113. data/lib/id3taginator/frames/text/tsse_encoder_frame.rb +40 -0
  114. data/lib/id3taginator/frames/text/txxx_user_text_info_frame.rb +51 -0
  115. data/lib/id3taginator/frames/text/tyer_year_frame.rb +42 -0
  116. data/lib/id3taginator/frames/text_frames.rb +840 -0
  117. data/lib/id3taginator/frames/tos/entities/ownership.rb +26 -0
  118. data/lib/id3taginator/frames/tos/entities/terms_of_use.rb +24 -0
  119. data/lib/id3taginator/frames/tos/owne_ownership_frame.rb +53 -0
  120. data/lib/id3taginator/frames/tos/user_terms_of_use_frame.rb +49 -0
  121. data/lib/id3taginator/frames/tos_frames.rb +54 -0
  122. data/lib/id3taginator/frames/ufid/entities/ufid_info.rb +24 -0
  123. data/lib/id3taginator/frames/ufid/ufid_unique_file_identifier_frame.rb +47 -0
  124. data/lib/id3taginator/frames/ufid_frames.rb +40 -0
  125. data/lib/id3taginator/frames/url/entities/user_info.rb +24 -0
  126. data/lib/id3taginator/frames/url/wcom_commercial_url_frame.rb +40 -0
  127. data/lib/id3taginator/frames/url/wcop_copyright_url_frame.rb +40 -0
  128. data/lib/id3taginator/frames/url/woaf_official_file_webpage_frame.rb +40 -0
  129. data/lib/id3taginator/frames/url/woar_official_artist_webpage_frame.rb +40 -0
  130. data/lib/id3taginator/frames/url/woas_official_source_webpage_frame.rb +40 -0
  131. data/lib/id3taginator/frames/url/wors_official_radio_station_homepage_frame.rb +40 -0
  132. data/lib/id3taginator/frames/url/wpay_payment_url_frame.rb +40 -0
  133. data/lib/id3taginator/frames/url/wpub_official_publisher_webpage_frame.rb +40 -0
  134. data/lib/id3taginator/frames/url/wxxx_user_url_link_frame.rb +50 -0
  135. data/lib/id3taginator/frames/url_frames.rb +195 -0
  136. data/lib/id3taginator/genres.rb +168 -0
  137. data/lib/id3taginator/header/id3v23_extended_header.rb +37 -0
  138. data/lib/id3taginator/header/id3v24_extended_header.rb +100 -0
  139. data/lib/id3taginator/header/id3v2_flags.rb +64 -0
  140. data/lib/id3taginator/id3v1_tag.rb +156 -0
  141. data/lib/id3taginator/id3v22_tag.rb +30 -0
  142. data/lib/id3taginator/id3v23_tag.rb +63 -0
  143. data/lib/id3taginator/id3v24_tag.rb +75 -0
  144. data/lib/id3taginator/id3v2_tag.rb +241 -0
  145. data/lib/id3taginator/options/options.rb +33 -0
  146. data/lib/id3taginator/util/compress_util.rb +25 -0
  147. data/lib/id3taginator/util/math_util.rb +68 -0
  148. data/lib/id3taginator/util/sync_util.rb +65 -0
  149. data/lib/id3taginator.rb +449 -0
  150. metadata +198 -0
@@ -0,0 +1,840 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Id3Taginator
4
+ module Frames
5
+ module TextFrames
6
+ include Frames::Frameable
7
+
8
+ # extracts the album (TALB/TAL)
9
+ #
10
+ # @return [String, nil] returns the Album
11
+ def album
12
+ find_frame(Text::AlbumFrame.frame_id(@major_version, @options))&.album
13
+ end
14
+
15
+ # sets the album (TALB/TAL)
16
+ #
17
+ # @param album [String] the album
18
+ def album=(album)
19
+ set_frame_fields(Text::AlbumFrame, [:@album], album)
20
+ end
21
+
22
+ # removes the album frame
23
+ def remove_album
24
+ @frames.delete_if { |f| f.frame_id == Text::AlbumFrame.frame_id(@major_version, @options) }
25
+ end
26
+
27
+ # extracts the album (TSOA)
28
+ #
29
+ # @return [String, nil] returns the Album Sort Order
30
+ def album_sort_order
31
+ find_frame(Text::AlbumSortOrderFrame.frame_id(@major_version, @options))&.album
32
+ end
33
+
34
+ # sets the album name used for sorting (TSOA)
35
+ #
36
+ # @param album [String] the album for sorting
37
+ def album_sort_order=(album)
38
+ set_frame_fields(Text::AlbumSortOrderFrame, [:@album], album)
39
+ end
40
+
41
+ # removes the album sort order frame
42
+ def remove_album_sort_order
43
+ @frames.delete_if { |f| f.frame_id == Text::AlbumSortOrderFrame.frame_id(@major_version, @options) }
44
+ end
45
+
46
+ # extracts the performer sort order (TSOP)
47
+ #
48
+ # @return [String, nil] returns the Performer Sort Order
49
+ def performer_sort_order
50
+ find_frame(Text::PerformerSortOrderFrame.frame_id(@major_version, @options))&.performer
51
+ end
52
+
53
+ # sets the performer used for sorting (TSOP)
54
+ #
55
+ # @param performer [String] the performer for sorting
56
+ def performer_sort_order=(performer)
57
+ set_frame_fields(Text::PerformerSortOrderFrame, [:@performer], performer)
58
+ end
59
+
60
+ # removes the performer sort order frame
61
+ def remove_performer_sort_order
62
+ @frames.delete_if { |f| f.frame_id == Text::PerformerSortOrderFrame.frame_id(@major_version, @options) }
63
+ end
64
+
65
+ # extracts the title sort order (TSOT)
66
+ #
67
+ # @return [String, nil] returns the Title Sort Order
68
+ def title_sort_order
69
+ find_frame(Text::TitleSortOrderFrame.frame_id(@major_version, @options))&.title
70
+ end
71
+
72
+ # sets the title used for sorting (TSOT)
73
+ #
74
+ # @param title [String] the title for sorting
75
+ def title_sort_order=(title)
76
+ set_frame_fields(Text::TitleSortOrderFrame, [:@title], title)
77
+ end
78
+
79
+ # removes the title sort order frame
80
+ def remove_title_sort_order
81
+ @frames.delete_if { |f| f.frame_id == Text::TitleSortOrderFrame.frame_id(@major_version, @options) }
82
+ end
83
+
84
+ # extracts the bpm (TBPM/TBP)
85
+ #
86
+ # @return [String, nil] returns the bpm
87
+ def bpm
88
+ find_frame(Text::BPMFrame.frame_id(@major_version, @options))&.bpm
89
+ end
90
+
91
+ # sets the bpm (TBPM/TBP)
92
+ #
93
+ # @param bpm [String, Integer] the bpm
94
+ def bpm=(bpm)
95
+ set_frame_fields(Text::BPMFrame, [:@bpm], bpm)
96
+ end
97
+
98
+ # removes the bpm frame
99
+ def remove_bpm
100
+ @frames.delete_if { |f| f.frame_id == Text::BPMFrame.frame_id(@major_version, @options) }
101
+ end
102
+
103
+ # extracts the composer (TCOM/TCM)
104
+ #
105
+ # @return [Array<String>] returns the composer
106
+ def composers
107
+ frame = find_frame(Text::ComposerFrame.frame_id(@major_version, @options))
108
+ return [] if frame.nil?
109
+
110
+ frame.composers
111
+ end
112
+
113
+ # sets the composers (TCOM/TCM)
114
+ #
115
+ # @param composers [Array<String>, String] the composers (or one composer)
116
+ def composers=(composers)
117
+ set_frame_fields(Text::ComposerFrame, [:@composers], composers)
118
+ end
119
+
120
+ # removes the composers frame
121
+ def remove_composers
122
+ @frames.delete_if { |f| f.frame_id == Text::ComposerFrame.frame_id(@major_version, @options) }
123
+ end
124
+
125
+ # extracts the genres (TCON/TCO)
126
+ #
127
+ # @return [Array<String>] returns the composer
128
+ def genres
129
+ frame = find_frame(Text::GenreFrame.frame_id(@major_version, @options))
130
+ return [] if frame.nil?
131
+
132
+ frame.genres
133
+ end
134
+
135
+ # sets the genres (TCON/TCO)
136
+ #
137
+ # @param genres [Array<String, Symbol>] the genres as String or Symbols
138
+ def genres=(genres)
139
+ set_frame_fields(Text::GenreFrame, [:@genres], genres)
140
+ end
141
+
142
+ # removes the genre frame
143
+ def remove_genres
144
+ @frames.delete_if { |f| f.frame_id == Text::GenreFrame.frame_id(@major_version, @options) }
145
+ end
146
+
147
+ # extracts the copyright (TCOP/TCR)
148
+ #
149
+ # @return [Frames::Text::Entities::Copyright, nil] returns the copyright
150
+ def copyright
151
+ frame = find_frame(Text::CopyrightFrame.frame_id(@major_version, @options))
152
+ return nil if frame.nil?
153
+
154
+ Text::Entities::Copyright.new(frame.year, frame.holder)
155
+ end
156
+
157
+ # sets the copyright (TCOP/TCR)
158
+ #
159
+ # @param copyright [Frames::Text::Entities::Copyright] the copyright
160
+ def copyright=(copyright)
161
+ set_frame_fields(Text::CopyrightFrame, %i[@year @holder], copyright.year, copyright.holder)
162
+ end
163
+
164
+ # removes the copyright frame
165
+ def remove_copyright
166
+ @frames.delete_if { |f| f.frame_id == Text::CopyrightFrame.frame_id(@major_version, @options) }
167
+ end
168
+
169
+ # extracts the date (TDAT/TDA)
170
+ #
171
+ # @return [Frames::Text::Entities::Date, nil] returns the date
172
+ def date
173
+ frame = find_frame(Text::DateFrame.frame_id(@major_version, @options))
174
+ return nil if frame.nil?
175
+
176
+ Text::Entities::Date.new(frame.month, frame.day)
177
+ end
178
+
179
+ # sets the date (TDAT/TDA)
180
+ #
181
+ # @param date [Frames::Text::Entities::Date] the date
182
+ def date=(date)
183
+ set_frame_fields(Text::DateFrame, %i[@month @day], date.month, date.day)
184
+ end
185
+
186
+ # removes the date frame
187
+ def remove_date
188
+ @frames.delete_if { |f| f.frame_id == Text::DateFrame.frame_id(@major_version, @options) }
189
+ end
190
+
191
+ # extracts the playlist delay (TDLY/TDY)
192
+ #
193
+ # @return [String, nil] returns the date
194
+ def playlist_delay
195
+ find_frame(Text::PlaylistDelayFrame.frame_id(@major_version, @options))&.delay
196
+ end
197
+
198
+ # sets the playlist delay (TDLY/TDY)
199
+ #
200
+ # @param delay_in_ms [String, Integer] the delay in ms
201
+ def playlist_delay=(delay_in_ms)
202
+ set_frame_fields(Text::PlaylistDelayFrame, [:@delay], delay_in_ms)
203
+ end
204
+
205
+ # removes the playlist delay frame
206
+ def remove_playlist_delay
207
+ @frames.delete_if { |f| f.frame_id == Text::PlaylistDelayFrame.frame_id(@major_version, @options) }
208
+ end
209
+
210
+ # extracts the encoded by (TENC/TEN)
211
+ #
212
+ # @return [String, nil] returns the encoded by
213
+ def encoded_by
214
+ find_frame(Text::EncodedByFrame.frame_id(@major_version, @options))&.encoded_by
215
+ end
216
+
217
+ # sets the playlist delay (TENC/TEN)
218
+ #
219
+ # @param encoded_by [String] the encoded by
220
+ def encoded_by=(encoded_by)
221
+ set_frame_fields(Text::EncodedByFrame, [:@encoded_by], encoded_by)
222
+ end
223
+
224
+ # removes the encoded by frame
225
+ def remove_encoded_by
226
+ @frames.delete_if { |f| f.frame_id == Text::EncodedByFrame.frame_id(@major_version, @options) }
227
+ end
228
+
229
+ # extracts the writers (TEXT/TXT)
230
+ #
231
+ # @return [Array<String>] returns the writers
232
+ def writers
233
+ frame = find_frame(Text::WritersFrame.frame_id(@major_version, @options))
234
+ return [] if frame.nil?
235
+
236
+ frame.writers
237
+ end
238
+
239
+ # sets the writers (TENC/TEN)
240
+ #
241
+ # @param writers [Array<String>, String] the writers
242
+ def writers=(writers)
243
+ set_frame_fields(Text::WritersFrame, [:@writers], writers)
244
+ end
245
+
246
+ # removes the writers frame
247
+ def remove_writers
248
+ @frames.delete_if { |f| f.frame_id == Text::WritersFrame.frame_id(@major_version, @options) }
249
+ end
250
+
251
+ # extracts the file type (TFLT/TFT)
252
+ #
253
+ # @return [String, nil] returns the file type
254
+ def file_type
255
+ find_frame(Text::FileTypeFrame.frame_id(@major_version, @options))&.file_type
256
+ end
257
+
258
+ # sets the file type (TFLT/TFT)
259
+ #
260
+ # @param file_type [String] the file type
261
+ def file_type=(file_type)
262
+ set_frame_fields(Text::FileTypeFrame, [:@file_type], file_type)
263
+ end
264
+
265
+ # removes the file type frame
266
+ def remove_file_type
267
+ @frames.delete_if { |f| f.frame_id == Text::FileTypeFrame.frame_id(@major_version, @options) }
268
+ end
269
+
270
+ # extracts the time (TIME/TIM)
271
+ #
272
+ # @return [Frames::Text::Entities::Time, nil] returns the time
273
+ def time
274
+ frame = find_frame(Text::TimeFrame.frame_id(@major_version, @options))
275
+ return nil if frame.nil?
276
+
277
+ Text::Entities::Time.new(frame.hours, frame.minutes)
278
+ end
279
+
280
+ # sets the time (TIME/TIM)
281
+ #
282
+ # @param time [Frames::Text::Entities::Time] the time
283
+ def time=(time)
284
+ set_frame_fields(Text::TimeFrame, %i[@hours @minutes], time.hours, time.minutes)
285
+ end
286
+
287
+ # removes the time frame
288
+ def remove_time
289
+ @frames.delete_if { |f| f.frame_id == Text::TimeFrame.frame_id(@major_version, @options) }
290
+ end
291
+
292
+ # extracts the content group description (TIT1/TT1)
293
+ #
294
+ # @return [String, nil] returns content group description
295
+ def content_group_description
296
+ find_frame(Text::ContentGroupDescriptionFrame.frame_id(@major_version, @options))&.content_description
297
+ end
298
+
299
+ # sets the content group description (TIT1/TT1)
300
+ #
301
+ # @param content_group_description [String] the content group description
302
+ def content_group_description=(content_group_description)
303
+ set_frame_fields(Text::ContentGroupDescriptionFrame, [:@content_group_description], content_group_description)
304
+ end
305
+
306
+ # removes the content group description frame
307
+ def remove_content_group_description
308
+ @frames.delete_if { |f| f.frame_id == Text::ContentGroupDescriptionFrame.frame_id(@major_version, @options) }
309
+ end
310
+
311
+ # extracts the title (TIT2/TT2)
312
+ #
313
+ # @return [String, nil] returns title
314
+ def title
315
+ find_frame(Text::TitleFrame.frame_id(@major_version, @options))&.title
316
+ end
317
+
318
+ # sets the title (TIT2/TT2)
319
+ #
320
+ # @param title [String] the title
321
+ def title=(title)
322
+ set_frame_fields(Text::TitleFrame, [:@title], title)
323
+ end
324
+
325
+ # removes the title frame
326
+ def remove_title
327
+ @frames.delete_if { |f| f.frame_id == Text::TitleFrame.frame_id(@major_version, @options) }
328
+ end
329
+
330
+ # extracts the subtitle (TIT3/TT3)
331
+ #
332
+ # @return [String, nil] returns subtitle
333
+ def subtitle
334
+ find_frame(Text::SubtitleFrame.frame_id(@major_version, @options))&.subtitle
335
+ end
336
+
337
+ # sets the subtitle (TIT3/TT3)
338
+ #
339
+ # @param subtitle [String] the subtitle
340
+ def subtitle=(subtitle)
341
+ set_frame_fields(Text::SubtitleFrame, [:@subtitle], subtitle)
342
+ end
343
+
344
+ # removes the subtitle frame
345
+ def remove_subtitle
346
+ @frames.delete_if { |f| f.frame_id == Text::SubtitleFrame.frame_id(@major_version, @options) }
347
+ end
348
+
349
+ # extracts the initial key (<= 3 characters) (TKEY/TKE)
350
+ #
351
+ # @return [String, nil] returns the initial key
352
+ def initial_key
353
+ find_frame(Text::InitialKeyFrame.frame_id(@major_version, @options))&.initial_key
354
+ end
355
+
356
+ # sets the initial key (<= 3 characters) (TKEY/TKE)
357
+ #
358
+ # @param initial_key [String] the initial key (<= 3 characters)
359
+ def initial_key=(initial_key)
360
+ set_frame_fields(Text::InitialKeyFrame, [:@initial_key], initial_key)
361
+ end
362
+
363
+ # removes the initial key frame
364
+ def remove_initial_key
365
+ @frames.delete_if { |f| f.frame_id == Text::InitialKeyFrame.frame_id(@major_version, @options) }
366
+ end
367
+
368
+ # extracts the languages (TLAN/TLA)
369
+ #
370
+ # @return [Array<String>] returns the languages
371
+ def languages
372
+ frame = find_frame(Text::LanguageFrame.frame_id(@major_version, @options))
373
+ return [] if frame.nil?
374
+
375
+ frame.languages
376
+ end
377
+
378
+ # sets the languages (TLAN/TLA)
379
+ #
380
+ # @param languages [Array<String>, String] the languages (3 character code languages)
381
+ def languages=(languages)
382
+ set_frame_fields(Text::LanguageFrame, [:@languages], languages)
383
+ end
384
+
385
+ # removes the languages frame
386
+ def remove_languages
387
+ @frames.delete_if { |f| f.frame_id == Text::LanguageFrame.frame_id(@major_version, @options) }
388
+ end
389
+
390
+ # extracts the length in seconds (TLEN/TLE)
391
+ #
392
+ # @return [String, nil] returns the length
393
+ def length
394
+ find_frame(Text::LengthFrame.frame_id(@major_version, @options))&.length
395
+ end
396
+
397
+ # sets the length in seconds (TLEN/TLE)
398
+ #
399
+ # @param length [String, Integer] the length in seconds
400
+ def length=(length)
401
+ set_frame_fields(Text::LengthFrame, [:@length], length)
402
+ end
403
+
404
+ # removes the length frame
405
+ def remove_length
406
+ @frames.delete_if { |f| f.frame_id == Text::LengthFrame.frame_id(@major_version, @options) }
407
+ end
408
+
409
+ # extracts the media type (TMED/TMT)
410
+ #
411
+ # @return [String, nil] returns the media type
412
+ def media_type
413
+ find_frame(Text::MediaTypeFrame.frame_id(@major_version, @options))&.media_type
414
+ end
415
+
416
+ # sets the media type (TMED/TMT)
417
+ #
418
+ # @param media_type [String] the media type
419
+ def media_type=(media_type)
420
+ set_frame_fields(Text::MediaTypeFrame, [:@media_type], media_type)
421
+ end
422
+
423
+ # removes the media type frame
424
+ def remove_media_type
425
+ @frames.delete_if { |f| f.frame_id == Text::MediaTypeFrame.frame_id(@major_version, @options) }
426
+ end
427
+
428
+ # extracts the original album (TOAL/TOT)
429
+ #
430
+ # @return [String, nil] returns the original album
431
+ def original_album
432
+ find_frame(Text::OriginalAlbumFrame.frame_id(@major_version, @options))&.original_album
433
+ end
434
+
435
+ # sets the original album (TOAL/TOT)
436
+ #
437
+ # @param original_album [String] the original album
438
+ def original_album=(original_album)
439
+ set_frame_fields(Text::OriginalAlbumFrame, [:@original_album], original_album)
440
+ end
441
+
442
+ # removes the original album frame
443
+ def remove_original_album
444
+ @frames.delete_if { |f| f.frame_id == Text::OriginalAlbumFrame.frame_id(@major_version, @options) }
445
+ end
446
+
447
+ # extracts the original file name (TOFN/TOF)
448
+ #
449
+ # @return [String, nil] returns the original file name
450
+ def original_filename
451
+ find_frame(Text::OriginalFilenameFrame.frame_id(@major_version, @options))&.original_filename
452
+ end
453
+
454
+ # sets the original filename (TOFN/TOF)
455
+ #
456
+ # @param original_filename [String] the original filename
457
+ def original_filename=(original_filename)
458
+ set_frame_fields(Text::OriginalFilenameFrame, [:@original_filename], original_filename)
459
+ end
460
+
461
+ # removes the original filename frame
462
+ def remove_original_filename
463
+ @frames.delete_if { |f| f.frame_id == Text::OriginalFilenameFrame.frame_id(@major_version, @options) }
464
+ end
465
+
466
+ # extracts the original writers (TOLY/TOL)
467
+ #
468
+ # @return [Array<String>] returns the original writers
469
+ def original_writers
470
+ frame = find_frame(Text::OriginalWritersFrame.frame_id(@major_version, @options))
471
+ return [] if frame.nil?
472
+
473
+ frame.original_writers
474
+ end
475
+
476
+ # sets the original writers (TOLY/TOL)
477
+ #
478
+ # @param original_writers [Array<String>, String] the original writers
479
+ def original_writers=(original_writers)
480
+ set_frame_fields(Text::OriginalWritersFrame, [:@original_writers], original_writers)
481
+ end
482
+
483
+ # removes the original writers frame
484
+ def remove_original_writers
485
+ @frames.delete_if { |f| f.frame_id == Text::OriginalWritersFrame.frame_id(@major_version, @options) }
486
+ end
487
+
488
+ # extracts the original artists (TOPE, :TOA)
489
+ #
490
+ # @return [Array<String>] returns the original artists
491
+ def original_artists
492
+ frame = find_frame(Text::OriginalArtistsFrame.frame_id(@major_version, @options))
493
+ return [] if frame.nil?
494
+
495
+ frame.original_artists
496
+ end
497
+
498
+ # sets the original artists (TOPE, :TOA)
499
+ #
500
+ # @param original_artists [Array<String>, String] the original artists
501
+ def original_artists=(original_artists)
502
+ set_frame_fields(Text::OriginalArtistsFrame, [:@original_artists], original_artists)
503
+ end
504
+
505
+ # removes the original artists frame
506
+ def remove_original_artists
507
+ @frames.delete_if { |f| f.frame_id == Text::OriginalArtistsFrame.frame_id(@major_version, @options) }
508
+ end
509
+
510
+ # extracts the original release year (TORY, :TOR)
511
+ #
512
+ # @return [String, nil] returns the original album
513
+ def original_release_year
514
+ find_frame(Text::OriginalReleaseYearFrame.frame_id(@major_version, @options))&.original_release_year
515
+ end
516
+
517
+ # sets the original release year (TORY, :TOR)
518
+ #
519
+ # @param original_release_year [String, Integer] the original release year
520
+ def original_release_year=(original_release_year)
521
+ set_frame_fields(Text::OriginalReleaseYearFrame, [:@original_release_year], original_release_year)
522
+ end
523
+
524
+ # removes the original release year frame
525
+ def remove_original_release_year
526
+ @frames.delete_if { |f| f.frame_id == Text::OriginalReleaseYearFrame.frame_id(@major_version, @options) }
527
+ end
528
+
529
+ # extracts the file owner (TOWN)
530
+ #
531
+ # @return [String, nil] returns the file owner
532
+ def file_owner
533
+ find_frame(Text::FileOwnerFrame.frame_id(@major_version, @options))&.file_owner
534
+ end
535
+
536
+ # sets the file owner (TOWN)
537
+ #
538
+ # @param file_owner [String] the file owner
539
+ def file_owner=(file_owner)
540
+ set_frame_fields(Text::FileOwnerFrame, [:@file_owner], file_owner)
541
+ end
542
+
543
+ # removes the file owner frame
544
+ def remove_file_owner
545
+ @frames.delete_if { |f| f.frame_id == Text::FileOwnerFrame.frame_id(@major_version, @options) }
546
+ end
547
+
548
+ # extracts the artists (TPE1/TP1)
549
+ #
550
+ # @return [Array<String>] returns the artists
551
+ def artists
552
+ frame = find_frame(Text::ArtistsFrame.frame_id(@major_version, @options))
553
+ return [] if frame.nil?
554
+
555
+ frame.artists
556
+ end
557
+
558
+ # sets the artists (TPE1/TP1)
559
+ #
560
+ # @param artists [Array<String>, String] the artists
561
+ def artists=(artists)
562
+ set_frame_fields(Text::ArtistsFrame, [:@artists], artists)
563
+ end
564
+
565
+ # removes the artists frame
566
+ def remove_artists
567
+ @frames.delete_if { |f| f.frame_id == Text::ArtistsFrame.frame_id(@major_version, @options) }
568
+ end
569
+
570
+ # extracts the album artist (TPE2/TP2)
571
+ #
572
+ # @return [String, nil] returns the album artist
573
+ def album_artist
574
+ find_frame(Text::AlbumArtistFrame.frame_id(@major_version, @options))&.album_artist
575
+ end
576
+
577
+ # sets the album artist (TPE2/TP2)
578
+ #
579
+ # @param album_artist [String] the album artist
580
+ def album_artist=(album_artist)
581
+ set_frame_fields(Text::AlbumArtistFrame, [:@album_artist], album_artist)
582
+ end
583
+
584
+ # removes the album artist frame
585
+ def remove_album_artist
586
+ @frames.delete_if { |f| f.frame_id == Text::AlbumArtistFrame.frame_id(@major_version, @options) }
587
+ end
588
+
589
+ # extracts the conductor (TPE3/TP3)
590
+ #
591
+ # @return [String, nil] returns the conductor
592
+ def conductor
593
+ find_frame(Text::ConductorFrame.frame_id(@major_version, @options))&.conductor
594
+ end
595
+
596
+ # sets the conductor (TPE3/TP3)
597
+ #
598
+ # @param conductor [String] the conductor
599
+ def conductor=(conductor)
600
+ set_frame_fields(Text::ConductorFrame, [:@conductor], conductor)
601
+ end
602
+
603
+ # removes the conductor frame
604
+ def remove_conductor
605
+ @frames.delete_if { |f| f.frame_id == Text::ConductorFrame.frame_id(@major_version, @options) }
606
+ end
607
+
608
+ # extracts the modified by (TPE4/TP4)
609
+ #
610
+ # @return [String, nil] returns the modified by
611
+ def modified_by
612
+ find_frame(Text::ModifiedByFrame.frame_id(@major_version, @options))&.modified_by
613
+ end
614
+
615
+ # sets the modified by (TPE4/TP4)
616
+ #
617
+ # @param modified_by [String] the modified_by
618
+ def modified_by=(modified_by)
619
+ set_frame_fields(Text::ModifiedByFrame, [:@modified_by], modified_by)
620
+ end
621
+
622
+ # removes the modified by frame
623
+ def remove_modified_by
624
+ @frames.delete_if { |f| f.frame_id == Text::ModifiedByFrame.frame_id(@major_version, @options) }
625
+ end
626
+
627
+ # extracts the part of set, e.g. CD 1/2 (TPOS/TPA)
628
+ #
629
+ # @return [Frames::Text::Entities::PartOfSet, nil] returns the part of set
630
+ def part_of_set
631
+ frame = find_frame(Text::PartOfSetFrame.frame_id(@major_version, @options))
632
+ return nil if frame.nil?
633
+
634
+ Text::Entities::PartOfSet.new(frame.part, frame.total)
635
+ end
636
+
637
+ # sets the part of set (TPOS/TPA)
638
+ #
639
+ # @param part_of_set [Frames::Text::Entities::PartOfSet] the part of set
640
+ def part_of_set=(part_of_set)
641
+ set_frame_fields(Text::PartOfSetFrame, %i[@part @htotal], part_of_set.part, part_of_set.total)
642
+ end
643
+
644
+ # removes the part of set frame
645
+ def remove_part_of_set
646
+ @frames.delete_if { |f| f.frame_id == Text::PartOfSetFrame.frame_id(@major_version, @options) }
647
+ end
648
+
649
+ # extracts the publisher (TPUB/TPB)
650
+ #
651
+ # @return [String, nil] returns the publisher
652
+ def publisher
653
+ find_frame(Text::PublisherFrame.frame_id(@major_version, @options))&.publisher
654
+ end
655
+
656
+ # sets the publisher (TPUB/TPB)
657
+ #
658
+ # @param publisher [String] the publisher
659
+ def publisher=(publisher)
660
+ set_frame_fields(Text::PublisherFrame, [:@publisher], publisher)
661
+ end
662
+
663
+ # removes the publisher frame
664
+ def remove_publisher
665
+ @frames.delete_if { |f| f.frame_id == Text::PublisherFrame.frame_id(@major_version, @options) }
666
+ end
667
+
668
+ # extracts the track number (TRCK/TRK)
669
+ #
670
+ # @return [Frames::Text::Entities::TrackNumber, nil] returns the track number
671
+ def track_number
672
+ frame = find_frame(Text::TrackNumberFrame.frame_id(@major_version, @options))
673
+ return nil if frame.nil?
674
+
675
+ Text::Entities::TrackNumber.new(frame.track_number, frame.total)
676
+ end
677
+
678
+ # sets the track number (TRCK/TRK)
679
+ #
680
+ # @param track_number [Frames::Text::Entities::TrackNumber] the track number
681
+ def track_number=(track_number)
682
+ set_frame_fields(Text::TrackNumberFrame, %i[@track_number @htotal], track_number.track_number,
683
+ track_number.total)
684
+ end
685
+
686
+ # removes the track number frame
687
+ def remove_track_number
688
+ @frames.delete_if { |f| f.frame_id == Text::TrackNumberFrame.frame_id(@major_version, @options) }
689
+ end
690
+
691
+ # extracts the recording dates (TRDA/TRD)
692
+ #
693
+ # @return [Array<String>] returns the recording dates
694
+ def recording_dates
695
+ frame = find_frame(Text::RecordingDatesFrame.frame_id(@major_version, @options))
696
+ return [] if frame.nil?
697
+
698
+ frame.recording_dates
699
+ end
700
+
701
+ # sets the recording dates (TRDA/TRD)
702
+ #
703
+ # @param recording_dates [Array<String>, String] the recording date(s)
704
+ def recording_dates=(recording_dates)
705
+ set_frame_fields(Text::RecordingDatesFrame, [:@recording_dates], recording_dates)
706
+ end
707
+
708
+ # removes the recording dates frame
709
+ def remove_recording_dates
710
+ @frames.delete_if { |f| f.frame_id == Text::RecordingDatesFrame.frame_id(@major_version, @options) }
711
+ end
712
+
713
+ # extracts the internet radio station name (TRSN)
714
+ #
715
+ # @return [String, nil] returns the internet radio station name
716
+ def internet_radio_station_name
717
+ find_frame(Text::InternetRadioStationFrame.frame_id(@major_version, @options))&.station_name
718
+ end
719
+
720
+ # sets the internet radio station (TRSN)
721
+ #
722
+ # @param station_name [String] the internet radio station
723
+ def internet_radio_station_name=(station_name)
724
+ set_frame_fields(Text::InternetRadioStationFrame, [:@station_name], station_name)
725
+ end
726
+
727
+ # removes the internet radio station name frame
728
+ def remove_internet_radio_station_name
729
+ @frames.delete_if { |f| f.frame_id == Text::InternetRadioStationFrame.frame_id(@major_version, @options) }
730
+ end
731
+
732
+ # extracts the file size in bytes excluding the id3v2 tag size (TSIZ/TSI)
733
+ #
734
+ # @return [String, nil] returns the size in bytes
735
+ def size
736
+ find_frame(Text::SizeFrame.frame_id(@major_version, @options))&.size
737
+ end
738
+
739
+ # sets the file size in bytes excluding the id3v2 tag size (TSIZ/TSI)
740
+ #
741
+ # @param size [String, Integer] the size in bytes
742
+ def size=(size)
743
+ set_frame_fields(Text::SizeFrame, [:@size], size)
744
+ end
745
+
746
+ # removes the size frame
747
+ def remove_size
748
+ @frames.delete_if { |f| f.frame_id == Text::SizeFrame.frame_id(@major_version, @options) }
749
+ end
750
+
751
+ # extracts the ISRC number (12 characters) (TSRC/TRC)
752
+ #
753
+ # @return [String, nil] returns the ISRC number
754
+ def isrc
755
+ find_frame(Text::ISRCFrame.frame_id(@major_version, @options))&.isrc
756
+ end
757
+
758
+ # sets the ISRC number (TSRC/TRC)
759
+ #
760
+ # @param isrc [String] the ISRC number (12 characters)
761
+ def isrc=(isrc)
762
+ set_frame_fields(Text::ISRCFrame, [:@isrc], isrc)
763
+ end
764
+
765
+ # removes the ISRC frame
766
+ def remove_isrc
767
+ @frames.delete_if { |f| f.frame_id == Text::ISRCFrame.frame_id(@major_version, @options) }
768
+ end
769
+
770
+ # extracts the encoder (TSSE/TSS)
771
+ #
772
+ # @return [String, nil] returns the Encoder
773
+ def encoder
774
+ find_frame(Text::EncoderFrame.frame_id(@major_version, @options))&.encoder
775
+ end
776
+
777
+ # sets the Encoder (TSSE/TSS)
778
+ #
779
+ # @param encoder [String] the Encoder
780
+ def encoder=(encoder)
781
+ set_frame_fields(Text::EncoderFrame, [:@encoder], encoder)
782
+ end
783
+
784
+ # removes the encoder frame
785
+ def remove_encoder
786
+ @frames.delete_if { |f| f.frame_id == Text::EncoderFrame.frame_id(@major_version, @options) }
787
+ end
788
+
789
+ # extracts the year (TYER/TYE)
790
+ #
791
+ # @return [String, nil] returns the year
792
+ def year
793
+ find_frame(Text::YearFrame.frame_id(@major_version, @options))&.year
794
+ end
795
+
796
+ # sets the Year (TYER/TYE)
797
+ #
798
+ # @param year [String, Integer] the Year, must be 4 characters long e.g. 2020
799
+ def year=(year)
800
+ set_frame_fields(Text::YearFrame, [:@year], year)
801
+ end
802
+
803
+ # removes the year frame
804
+ def remove_year
805
+ @frames.delete_if { |f| f.frame_id == Text::YearFrame.frame_id(@major_version, @options) }
806
+ end
807
+
808
+ # extracts the user text infos (TXXX/TXX)
809
+ #
810
+ # @return [Array<Frames::Text::Entities::UserInfo>] returns the User Text Infos
811
+ def user_custom_text_information
812
+ frame = find_frames(Text::UserTextInfoFrame.frame_id(@major_version, @options))
813
+ return [] if frame.nil? || frame.empty?
814
+
815
+ frame.map { |f| Text::Entities::UserInfo.new(f.description, f.content) }
816
+ end
817
+
818
+ # adds a user text info (TXXX/TXX)
819
+ # Multiple ones can be added, as long as they have different description
820
+ #
821
+ # @param information [Frames::Text::Entities::UserInfo] the user text info to add
822
+ def user_custom_text_information=(information)
823
+ set_frame_fields_by_selector(Text::UserTextInfoFrame, %i[@description @content],
824
+ ->(f) { f.description == information.description },
825
+ information.description, information.content)
826
+ end
827
+
828
+ alias add_user_custom_text_information user_custom_text_information=
829
+
830
+ # removes a user text info for the specific description (TXXX/TXX)
831
+ #
832
+ # @param description [String] the description
833
+ def remove_user_custom_text_information(description)
834
+ @frames.delete_if do |f|
835
+ f.frame_id == Text::UserTextInfoFrame.frame_id(@major_version, @options) && f.description == description
836
+ end
837
+ end
838
+ end
839
+ end
840
+ end