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.
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