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
data/README.md
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# Id3taginator
|
|
2
|
+
|
|
3
|
+
- [Introduction](#introduction)
|
|
4
|
+
- [Installation](#installation)
|
|
5
|
+
- [Implemented Frames](#implemented-frames)
|
|
6
|
+
- [Usage](#usage)
|
|
7
|
+
* [Read Tags](#read-tags)
|
|
8
|
+
* [Modify Tag](#modify-tag)
|
|
9
|
+
+ [Remove Tag](#remove-tag)
|
|
10
|
+
+ [Modify existing Frame](#modify-existing-frame)
|
|
11
|
+
+ [Create new Tag](#create-new-tag)
|
|
12
|
+
- [What is the difference?](#what-is-the-difference-)
|
|
13
|
+
* [Write Audio File with modified Tags](#write-audio-file-with-modified-tags)
|
|
14
|
+
* [Options](#options)
|
|
15
|
+
- [default_encode_dest](#default-encode-dest)
|
|
16
|
+
- [default_decode_dest](#default-decode-dest)
|
|
17
|
+
- [padding_bytes](#padding-bytes)
|
|
18
|
+
- [ignore_v23_frame_error](#ignore-v23-frame-error)
|
|
19
|
+
- [ignore_v24_frame_error](#ignore-v24-frame-error)
|
|
20
|
+
- [add_size_frame](#add-size-frame)
|
|
21
|
+
+ [How to set Options](#how-to-set-options)
|
|
22
|
+
* [Create Entities](#create-entities)
|
|
23
|
+
* [Custom Frames](#custom-frames)
|
|
24
|
+
- [Development](#development)
|
|
25
|
+
- [Contributing](#contributing)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
- [Code of Conduct](#code-of-conduct)
|
|
28
|
+
|
|
29
|
+
## Introduction
|
|
30
|
+
|
|
31
|
+
Id3Taginator is a ID3v1, ID3v2.2/3/4 [tag reader](https://en.wikipedia.org/wiki/ID3) and writer fully written in Ruby and does not
|
|
32
|
+
rely on TagLib or any other 3rd party library to read/write iD3 Tags. It aims to offer a simple
|
|
33
|
+
way to read and write ID3Tags.
|
|
34
|
+
It follows the specifications as seen here:
|
|
35
|
+
* ID3v1 - https://id3.org/ID3v1
|
|
36
|
+
* ID3v2.2 - https://id3.org/id3v2-00
|
|
37
|
+
* Id3v2.3 - https://id3.org/id3v2.3.0
|
|
38
|
+
* Id3v2.4 - https://id3.org/id3v2.4.0-structure / https://id3.org/id3v2.4.0-frames
|
|
39
|
+
|
|
40
|
+
It can write ID3v1 and ID3v2 to the same file. For ID3v2 only 1 version can be used.
|
|
41
|
+
It is recommended to stick to ID3v2.3, because for now, it seems to be the most supported version.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
from [rubygems](https://rubygems.org/gems/id3taginator)
|
|
46
|
+
|
|
47
|
+
```shell
|
|
48
|
+
gem 'id3taginator'
|
|
49
|
+
```
|
|
50
|
+
or from the sources using
|
|
51
|
+
```shell
|
|
52
|
+
gem build id3taginator.gemspec
|
|
53
|
+
```
|
|
54
|
+
and then execute
|
|
55
|
+
```shell
|
|
56
|
+
gem install id3taginator-x.x.x.gem
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Implemented Frames
|
|
60
|
+
|
|
61
|
+
The following frames are implemented and fully supported. Not implemented frames can still be added by using a custom frame.
|
|
62
|
+
See more about custom frames in the _Usage_ part. Most Frames are self explaining. For other documentation about the frames and their meaning,
|
|
63
|
+
please check the documentation - [ID3v1](https://id3.org/ID3v1), [ID3v2.2](https://id3.org/id3v2-00),
|
|
64
|
+
[Id3v2.3](https://id3.org/id3v2.3.0), [Id3v2.4](https://id3.org/id3v2.4.0-structure)
|
|
65
|
+
|
|
66
|
+
**Hint:** If a frame is currently not implemented, it can still be read and written using Custom Frames.
|
|
67
|
+
In this case, if an MP3 file is written that contains a not implemented frame, that frame will simply be saved as a
|
|
68
|
+
Custom Frame, can be modified as such and will be written as it was once the file is saved.
|
|
69
|
+
|
|
70
|
+
| Implemented | Frame | Description | ID3v2.2 | ID3v2.3 | ID3v2.4 |
|
|
71
|
+
| :---------: | ----- | --------------------------------------------------- | :-----: | :-----: | :-----: |
|
|
72
|
+
| x | AENC/CRA | Audio encryption | x | x | x |
|
|
73
|
+
| x | APIC/PIC | Attached picture | x | x | x |
|
|
74
|
+
| | ASPI | Audio seek point index | | | x |
|
|
75
|
+
| x | COMM/COM | Comments | x | x | x |
|
|
76
|
+
| | COMR | Commercial frame | | x | x |
|
|
77
|
+
| | CRM | Encrypted meta frame | x | | |
|
|
78
|
+
| x | ENCR | Encryption method registration | | x | x |
|
|
79
|
+
| | EQUA/EQU | Equalization | x | x | |
|
|
80
|
+
| | EQU2 | Equalization (2) | | | x |
|
|
81
|
+
| | ETCO/ETC | Event timing codes | x | x | x |
|
|
82
|
+
| x | GEOB/GEO | General encapsulated object | x | x | x |
|
|
83
|
+
| x | GRID | Group identification registration | | x | x |
|
|
84
|
+
| x | GRP1 | iTunes Grouping | | x | x |
|
|
85
|
+
| x | IPLS/PLS | Involved people list | x | x | x |
|
|
86
|
+
| | LINK/LNK | Linked information | x | x | x |
|
|
87
|
+
| x | MCDI/MCI | Music CD identifier | x | x | x |
|
|
88
|
+
| | MLLT/MLL | MPEG location lookup table | x | x | x |
|
|
89
|
+
| x | PCNT/CNT | Play counter | x | x | x |
|
|
90
|
+
| x | POPM/POP | Popularimeter | x | x | x |
|
|
91
|
+
| | POSS | Position synchronisation frame | | x | x |
|
|
92
|
+
| x | RBUF/BUF | Recommended buffer size | x | x | x |
|
|
93
|
+
| | RVAD/RVA | Relative volume adjustment | x | x | |
|
|
94
|
+
| | RVA2 | Relative volume adjustment (2) | | | x |
|
|
95
|
+
| | RVRB/REV | Reverb | x | x | x |
|
|
96
|
+
| | SEEK | Seek frame | | | x |
|
|
97
|
+
| | SIGN | Signature frame | | | x |
|
|
98
|
+
| | SYLT/SLT | Synchronized lyric/text | x | x | x |
|
|
99
|
+
| | SYTC/STC | Synchronized tempo codes | x | x | x |
|
|
100
|
+
| x | OWNE | Ownership frame | | x | x |
|
|
101
|
+
| x | PRIV | Private frame | | x | x |
|
|
102
|
+
| x | TALB/TAL | Album/Movie/Show title | x | x | x |
|
|
103
|
+
| x | TBPM/TBP | BPM (beats per minute) | x | x | x |
|
|
104
|
+
| x | TCOM/TCM | Composer | x | x | x |
|
|
105
|
+
| x | TCON/TCO | Content type | x | x | x |
|
|
106
|
+
| x | TCOP/TCR | Copyright message | x | x | x |
|
|
107
|
+
| x | TDAT/TDA | Date | x | x | x |
|
|
108
|
+
| | TDEN | Encoding time | | | x |
|
|
109
|
+
| x | TDLY/TDY | Playlist delay | x | x | x |
|
|
110
|
+
| | TDOR | Original release time | | | x |
|
|
111
|
+
| | TDRC | Recording time | | | x |
|
|
112
|
+
| | TDRL | Release time | | | x |
|
|
113
|
+
| | TDTG | Tagging time | | | x |
|
|
114
|
+
| x | TENC/TEN | Encoded by | x | x | x |
|
|
115
|
+
| x | TEXT/TXT | Lyricist/Text writer | x | x | x |
|
|
116
|
+
| x | TFLT/TFT | File type | x | x | x |
|
|
117
|
+
| x | TIME/TIM | Time | x | x | x |
|
|
118
|
+
| x | TIT1/TT1 | Content group description | x | x | x |
|
|
119
|
+
| x | TIT2/TT2 | Title/songname/content description | x | x | x |
|
|
120
|
+
| x | TIT3/TT3 | Subtitle/Description refinement | x | x | x |
|
|
121
|
+
| x | TKEY/TKE | Initial key | x | x | x |
|
|
122
|
+
| x | TLAN/TLA | Language(s) | x | x | x |
|
|
123
|
+
| x | TLEN/TLE | Length | x | x | x |
|
|
124
|
+
| | TMCL | Musician credits list | | | x |
|
|
125
|
+
| x | TMED/TMT | Media type | x | x | x |
|
|
126
|
+
| | TMOO | Mood | | | x |
|
|
127
|
+
| x | TOAL/TOT | Original album/movie/show title | x | x | x |
|
|
128
|
+
| x | TOFN/TOF | Original filename | x | x | x |
|
|
129
|
+
| x | TOLY/TOL | Original lyricist(s)/text writer(s) | x | x | x |
|
|
130
|
+
| x | TOPE/TOA | Original artist(s)/performer(s) | x | x | x |
|
|
131
|
+
| x | TORY/TOR | Original release year | x | x | x |
|
|
132
|
+
| x | TOWN | File owner/licensee | | x | x |
|
|
133
|
+
| x | TPE1/TP1 | Lead performer(s)/Soloist(s) | x | x | x |
|
|
134
|
+
| x | TPE2/TP2 | Band/orchestra/accompaniment | x | x | x |
|
|
135
|
+
| x | TPE3/TP3 | Conductor/performer refinement | x | x | x |
|
|
136
|
+
| x | TPE4/TP4 | Interpreted, remixed, or otherwise modified by | x | x | x |
|
|
137
|
+
| x | TPOS/TPA | Part of a set | x | x | x |
|
|
138
|
+
| | TPRO | Produced notice | | | x |
|
|
139
|
+
| x | TPUB/TPB | Publisher | x | x | x |
|
|
140
|
+
| x | TRCK/TRK | Track number/Position in set | x | x | x |
|
|
141
|
+
| x | TRDA/TRD | Recording dates | x | x | x |
|
|
142
|
+
| x | TRSN | Internet radio station name | | x | x |
|
|
143
|
+
| | TRSO | Internet radio station owner | | | x |
|
|
144
|
+
| x | TSIZ/TSI | Size | x | x | |
|
|
145
|
+
| x | TSOA | Album sort order | | | x |
|
|
146
|
+
| x | TSOP | Performer sort order | | | x |
|
|
147
|
+
| x | TSOT | Title sort order | | | x |
|
|
148
|
+
| x | TSRC/TRC | ISRC (international standard recording code) | x | x | x |
|
|
149
|
+
| x | TSSE/TSS | Software/Hardware and settings used for encoding | x | x | x |
|
|
150
|
+
| | TSST | Set subtitle | | | x |
|
|
151
|
+
| x | TXXX/TXX | User defined text information frame | x | x | x |
|
|
152
|
+
| x | TYER/TYE | Year | x | x | x |
|
|
153
|
+
| x | UFID/UFI | Unique file identifier | x | x | x |
|
|
154
|
+
| x | USER | Terms of use | | x | x |
|
|
155
|
+
| x | USLT/ULT | Unsynchronized lyric/text transcription | x | x | x |
|
|
156
|
+
| x | WCOM/WCM | Commercial information | x | x | x |
|
|
157
|
+
| x | WCOP/WCP | Copyright/Legal information | x | x | x |
|
|
158
|
+
| x | WOAF/WAF | Official audio file webpage | x | x | x |
|
|
159
|
+
| x | WOAR/WAR | Official artist/performer webpage | x | x | x |
|
|
160
|
+
| x | WOAS/WAS | Official audio source webpage | x | x | x |
|
|
161
|
+
| x | WORS | Official internet radio station homepage | | x | x |
|
|
162
|
+
| x | WPAY | Payment | | x | x |
|
|
163
|
+
| x | WPUB/WPB | Publishers official webpage | x | x | x |
|
|
164
|
+
| x | WXXX/WXX | User defined URL link frame | x | x | x |
|
|
165
|
+
|
|
166
|
+
## Usage
|
|
167
|
+
|
|
168
|
+
The usage is pretty straight forward. The audio file will be read and parsed, and provides access to all
|
|
169
|
+
available frames, allows to add or remove frames and finally, write the file.
|
|
170
|
+
|
|
171
|
+
To modify and/or read a tag, simply create an audio file:
|
|
172
|
+
```ruby
|
|
173
|
+
audio_file = Id3Taginator.build_by_path('path/to/audio_file')
|
|
174
|
+
```
|
|
175
|
+
this will automatically parse the ID3 tags, if an ID3tag is present.
|
|
176
|
+
|
|
177
|
+
### Read Tags
|
|
178
|
+
```ruby
|
|
179
|
+
v1_tag = audio_file.id3v1_tag
|
|
180
|
+
v1_tag.title # => 'ID3v1 Title'
|
|
181
|
+
v1_tag.artist # => 'ID3v1 Artist'
|
|
182
|
+
v1_tag.album # => 'ID3v1 Album'
|
|
183
|
+
|
|
184
|
+
# this can either be a ID3v2.2, ID3v2.3 or ID3v2.4 tag
|
|
185
|
+
v2_tag = audio_file.id3v2_tag
|
|
186
|
+
v2_tag.version # => 2.3.0
|
|
187
|
+
v2_tag.title # => 'ID3v2 Title'
|
|
188
|
+
v2_tag.artists # => ['ID3v2 Artist1', 'ID3v2 Artist2']
|
|
189
|
+
v2_tag.album # => 'ID3v2 Album'
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Modify Tag
|
|
193
|
+
|
|
194
|
+
existing tags can either be modified, or a new tag can be created, or an existing one removed.
|
|
195
|
+
|
|
196
|
+
#### Remove Tag
|
|
197
|
+
```ruby
|
|
198
|
+
audio_file.remove_id3v1_tag
|
|
199
|
+
audio_file.remove_id3v2_tag
|
|
200
|
+
```
|
|
201
|
+
will remove the ID3vX tags.
|
|
202
|
+
|
|
203
|
+
#### Modify existing Frame
|
|
204
|
+
|
|
205
|
+
There are already methods defined to modify a frame. Each frame has one. A Frame that is only allowed once, has only one Getter and one Setter.
|
|
206
|
+
If a Frame is present, the Setter will update the existing Frame. If no Frame it is present, it will create a new Frame.
|
|
207
|
+
|
|
208
|
+
If the Frame can be present multiple times, the Setter Method will update the existing frame, if a specific field with the unique identifier is the same (see the ruby doc to find out which field is the unique field).
|
|
209
|
+
In those cases, the Setter is `field=` or alternatively `add_field`, e.g. `comment=` and `add_comment(...)` are the same.
|
|
210
|
+
If no Frame with the unique field is present, a new Frame will be added.
|
|
211
|
+
|
|
212
|
+
The Getter methods will return nil if the Frame is not present or en empty array, if the frame is not present, but the result is an array.
|
|
213
|
+
|
|
214
|
+
```ruby
|
|
215
|
+
v1_tag = audio_file.id3v1_tag
|
|
216
|
+
v1_tag.title = 'My new Title'
|
|
217
|
+
v1_tag.title # => 'My new Title'
|
|
218
|
+
v1_tag.title = nil
|
|
219
|
+
v1_tag.title # => nil
|
|
220
|
+
|
|
221
|
+
v2_tag = audio_file.id3v2_tag
|
|
222
|
+
v2_tag.title = 'My new Title'
|
|
223
|
+
v2_tag.title # => 'My new Title'
|
|
224
|
+
v2_tag.remove_title
|
|
225
|
+
v2_tag.title # => nil
|
|
226
|
+
|
|
227
|
+
v2_tag.languages # => []
|
|
228
|
+
v2_tag.languages = %w[eng ger]
|
|
229
|
+
v2_tag.languages # ['eng', 'ger']
|
|
230
|
+
v2_tag.languages = %w[eng]
|
|
231
|
+
v2_tag.languages # ['eng']
|
|
232
|
+
v2_tag.remove_languages
|
|
233
|
+
v2_tag.languages # => []
|
|
234
|
+
|
|
235
|
+
v2_tag.comments # => []
|
|
236
|
+
v2_tag.add_comment(Id3Taginator.create_comment('eng', 'my descriptor', 'my comment'))
|
|
237
|
+
v2_tag.comments # => [Comment('eng', 'my descriptor', 'my comment')]
|
|
238
|
+
v2_tag.add_comment(Id3Taginator.create_comment('eng', 'another descriptor', 'my other comment'))
|
|
239
|
+
v2_tag.comments # => [Comment('eng', 'my descriptor', 'my comment'), Comment('eng', 'another descriptor', 'my other comment')]
|
|
240
|
+
v2_tag.add_comment(Id3Taginator.create_comment('eng', 'my descriptor', 'my modified comment'))
|
|
241
|
+
# descriptor and language are already present, so it will update the comment instead of creating a new one
|
|
242
|
+
v2_tag.comments # => [Comment('eng', 'my descriptor', 'my modified comment'), Comment('eng', 'another descriptor', 'my other comment')]
|
|
243
|
+
|
|
244
|
+
v2_tag.remove_comment('eng', 'my descriptor')
|
|
245
|
+
v2_tag.comments # => [Comment('eng', 'another descriptor', 'my other comment')]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Create new Tag
|
|
249
|
+
|
|
250
|
+
If no tag is present, or a new one should be created, a few simple methods are present:
|
|
251
|
+
```ruby
|
|
252
|
+
audio_file.create_id3v1_tag # => the id3v1_tag
|
|
253
|
+
audio_file.create_id3v2_2_tag # => the id3v22_tag
|
|
254
|
+
audio_file.create_id3v2_3_tag # => the id3v23_tag
|
|
255
|
+
audio_file.create_id3v2_4_tag # => the id3v24_tag
|
|
256
|
+
```
|
|
257
|
+
As mentioned before, it is recommended to use ID3v2.3, because it seems to be the most supported for version.
|
|
258
|
+
|
|
259
|
+
##### What is the difference?
|
|
260
|
+
|
|
261
|
+
ID3v2.2 is the oldest ID3v2 tag, and for example only uses 3 characters for the Frame ID and offers far less Frames as the successors.
|
|
262
|
+
It should be avoided, because it is kinda outdated.
|
|
263
|
+
|
|
264
|
+
ID3v2.3 and ID3v2.4 are very similar. ID3v2.4 added a few more frames, and allows 2 more encodings in comparison to ID3v2.3,
|
|
265
|
+
but most of the new added frames or changes are not game breaking and most probably not used by most people.
|
|
266
|
+
Some of the useful new frames like `Album Sort Order` or `Title Sort Order` are officially not part of ID3v2.3, but most players
|
|
267
|
+
will interpret them nevertheless, as long as they are present. Per default ID3Taginator allows to add those ID3v2.4 only frames even to
|
|
268
|
+
ID3v2.3 Tags.
|
|
269
|
+
|
|
270
|
+
### Write Audio File with modified Tags
|
|
271
|
+
|
|
272
|
+
Once a file is modified, it must be written to save the changes. To do this, Id3Taginator provides to 2 methods:
|
|
273
|
+
```ruby
|
|
274
|
+
audio_file.write_audio_file('path/to/new/file')
|
|
275
|
+
```
|
|
276
|
+
Which writes the modified file to the specified path. The audio data will be cached, so the file can be written to the same
|
|
277
|
+
path that is used to read the MP3 file, essentially overwriting it.
|
|
278
|
+
|
|
279
|
+
The other alternative is to write the result to a byte array represented as a String:
|
|
280
|
+
|
|
281
|
+
```ruby
|
|
282
|
+
audio_file.audio_file_to_bytes
|
|
283
|
+
```
|
|
284
|
+
This will return a byte array represented as a String (str.bytes) with the modified audio file, and the decision how to
|
|
285
|
+
handle it, is completely yours.
|
|
286
|
+
|
|
287
|
+
### Options
|
|
288
|
+
|
|
289
|
+
The following options are available:
|
|
290
|
+
##### default_encode_dest
|
|
291
|
+
This is the encoding that should be used to encode the data if applicable. For example most Text Frames are encoded
|
|
292
|
+
and the encoding byte is prefixed to the encoded data.
|
|
293
|
+
|
|
294
|
+
**Default** is `UTF-16`
|
|
295
|
+
|
|
296
|
+
##### default_decode_dest
|
|
297
|
+
This is more or less only for internal use and doesn't affect the written tag. This encoding is used to decode the tag if an encoding
|
|
298
|
+
is applied and later on, when the tag is written the `default_encode_dest` is used again.
|
|
299
|
+
|
|
300
|
+
**Default** is `UTF-8`
|
|
301
|
+
|
|
302
|
+
##### padding_bytes
|
|
303
|
+
After the last Frame is written, optionally padding null bytes can be written. Padding bytes can for example be used to add additionally information,
|
|
304
|
+
e.g. an `ID3 Footer` without rewriting the whole tag.
|
|
305
|
+
|
|
306
|
+
**Default** is `20`
|
|
307
|
+
|
|
308
|
+
##### ignore_v23_frame_error
|
|
309
|
+
|
|
310
|
+
Some Frames are available for ID3v2.4 but not for ID3v2.3, for example the Sort Order frames like TSOT.
|
|
311
|
+
But some application still interpret them correctly, hence they can be used in ID3v2.3 even if they are not
|
|
312
|
+
in the specifications. When this flag is true, no error will be raised if an invalid Frame should be added to the Tag.
|
|
313
|
+
In those cases it is for example possible to add an ID3v2.4 only Tag to an ID3v2.3 Tag.
|
|
314
|
+
|
|
315
|
+
**Default** is `true`
|
|
316
|
+
|
|
317
|
+
##### ignore_v24_frame_error
|
|
318
|
+
|
|
319
|
+
Same as `ignore_v23_frame_error` just for ID3v2.4 Tag.
|
|
320
|
+
|
|
321
|
+
**Default** is `true`
|
|
322
|
+
|
|
323
|
+
##### add_size_frame
|
|
324
|
+
|
|
325
|
+
ID3v2.3 has a size (TSIZ) frame that contains the file size in bytes without ID3v2 Tag size. When this flag is true
|
|
326
|
+
this Frame will be added automatically if it is not present.
|
|
327
|
+
|
|
328
|
+
Note: In ID3v2.4 this Frame was removed. So in order to use this flag for ID3v2.4 Tags, the flag `ignore_v24_frame_error`
|
|
329
|
+
must be `true` too.
|
|
330
|
+
|
|
331
|
+
**Default** is `false`
|
|
332
|
+
|
|
333
|
+
#### How to set Options
|
|
334
|
+
|
|
335
|
+
Options can be set on a global level, then those options will be applied to all Audio Files that are created,
|
|
336
|
+
or the option is only applied to one Audio File.
|
|
337
|
+
|
|
338
|
+
To define global options, simply create an `Id3Taginator` instance and apply the options:
|
|
339
|
+
```ruby
|
|
340
|
+
id3taginator = Id3Taginator.global_options
|
|
341
|
+
.default_encode_for_destination(Encoding::UTF_16)
|
|
342
|
+
.default_decode_for_destination(Encoding::UTF_8)
|
|
343
|
+
.tag_padding(42)
|
|
344
|
+
.ignore_v23_frame_error(true)
|
|
345
|
+
.ignore_v24_frame_error(false)
|
|
346
|
+
.add_size_frame(true)
|
|
347
|
+
|
|
348
|
+
audio_file = id3taginator.build_by_path('path/to/file')
|
|
349
|
+
# => options are applied
|
|
350
|
+
another_audio_file = id3taginator.build_by_path('path/to/another/file')
|
|
351
|
+
# => options are applied too
|
|
352
|
+
```
|
|
353
|
+
if options should be applied to one audio file, create the file and apply the options directly to this file
|
|
354
|
+
```ruby
|
|
355
|
+
audio_file = Id3Taginator.build_by_path('path/to/file')
|
|
356
|
+
audio_file.default_encode_for_destination(Encoding::UTF_16)
|
|
357
|
+
.default_decode_for_destination(Encoding::UTF_8)
|
|
358
|
+
.tag_padding(42)
|
|
359
|
+
.ignore_v23_frame_error(true)
|
|
360
|
+
.ignore_v24_frame_error(false)
|
|
361
|
+
.add_size_frame(true)
|
|
362
|
+
```
|
|
363
|
+
Here, the options are only applied to this Audio File instance. All other created instance use the default options.
|
|
364
|
+
|
|
365
|
+
### Create Entities
|
|
366
|
+
|
|
367
|
+
Some Setter such as `copyright=` or `add_picture` require an Entity Instance as an argument. All arguments can be created
|
|
368
|
+
like this
|
|
369
|
+
|
|
370
|
+
```ruby
|
|
371
|
+
Id3Taginator.create_buffer(42, false, 5)
|
|
372
|
+
Id3Taginator.create_picture_from_data('image/png', :COVER_FRONT, 'Description', 'Some picture data')
|
|
373
|
+
```
|
|
374
|
+
There is a create method for all Entities.
|
|
375
|
+
|
|
376
|
+
### Custom Frames
|
|
377
|
+
|
|
378
|
+
If a frame is currently not implemented, but is required, it can still be added or modified using Custom Frames. If the Frame is already
|
|
379
|
+
present in the ID3v2 Tag, then it will be available as a Custom Frame. Custom Frames can be added and modified as all other Frames
|
|
380
|
+
```ruby
|
|
381
|
+
# CSTM is the frame id of the frame we want to fetch
|
|
382
|
+
my_custom_frame = v2_tag.custom_frame('CSTM')
|
|
383
|
+
frame_content = my_custom_frame.content
|
|
384
|
+
# modify the content
|
|
385
|
+
v2_tag.add_custom_frame('CSTM', frame_content)
|
|
386
|
+
|
|
387
|
+
v2_tag.add_custom_frame('ABCD', 'my new frame content')
|
|
388
|
+
```
|
|
389
|
+
Here, the old content is replaced by the new content, and a new custom Frame is added.
|
|
390
|
+
If multiple custom frames with the same Frame ID should exist, an optional `selector_lambda` can be passed as an argument.
|
|
391
|
+
|
|
392
|
+
## Development
|
|
393
|
+
|
|
394
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
395
|
+
|
|
396
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
397
|
+
|
|
398
|
+
## Contributing
|
|
399
|
+
|
|
400
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/cfe86/id3taginator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/cfe86/id3taginator/blob/master/CODE_OF_CONDUCT.md).
|
|
401
|
+
|
|
402
|
+
## License
|
|
403
|
+
|
|
404
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
405
|
+
|
|
406
|
+
## Code of Conduct
|
|
407
|
+
|
|
408
|
+
Everyone interacting in the Id3taginator project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/cfe86/id3taginator/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'id3taginator'
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require 'irb'
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = 'id3taginator'
|
|
5
|
+
spec.version = '0.8'
|
|
6
|
+
spec.authors = ['Christian Feier']
|
|
7
|
+
spec.email = ['Christian.Feier@gmail.com']
|
|
8
|
+
|
|
9
|
+
spec.summary = 'Id3Taginator is a ID3v1, ID3v2.2/3/4 tag reader and writer fully written in Ruby and does not'\
|
|
10
|
+
'rely on TagLib or any other 3rd party library to read/write id3tags. It aims to offer a simple'\
|
|
11
|
+
'way to read and write ID3Tags.'
|
|
12
|
+
spec.description = 'Id3Taginator is a ID3v1, ID3v2.2/3/4 tag reader and writer fully written in Ruby and does not'\
|
|
13
|
+
'rely on TagLib or any other 3rd party library to read/write id3tags. It aims to offer a simple'\
|
|
14
|
+
'way to read and write ID3Tags.'
|
|
15
|
+
spec.homepage = 'https://github.com/cfe86/Id3Taginator'
|
|
16
|
+
spec.license = 'MIT'
|
|
17
|
+
spec.required_ruby_version = '>= 2.5.1'
|
|
18
|
+
|
|
19
|
+
spec.metadata['homepage_uri'] = 'https://github.com/cfe86/Id3Taginator'
|
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/cfe86/Id3Taginator'
|
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/cfe86/Id3Taginator'
|
|
22
|
+
|
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.bindir = 'exe'
|
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
30
|
+
spec.require_paths = ['lib']
|
|
31
|
+
|
|
32
|
+
# Uncomment to register a new dependency of your gem
|
|
33
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
|
34
|
+
|
|
35
|
+
# For more information and examples about making a new gem, checkout our
|
|
36
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
37
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Id3Taginator
|
|
4
|
+
class AudioFile
|
|
5
|
+
include Extensions::Optionable
|
|
6
|
+
|
|
7
|
+
attr_reader :id3v1_tag, :id3v2_tag
|
|
8
|
+
|
|
9
|
+
# constructor
|
|
10
|
+
#
|
|
11
|
+
# @param file [StringIO, IO, File] the file stream
|
|
12
|
+
# @param options [Options::Options] the options to use for this file
|
|
13
|
+
# @param no_tag_parsing [Boolean] if true, no tag parsing is done (only use this for testing purposes, otherwise it
|
|
14
|
+
# renders the file literally useless)
|
|
15
|
+
def initialize(file, options = Options::Options.new, no_tag_parsing: false)
|
|
16
|
+
@file = file
|
|
17
|
+
@options = options
|
|
18
|
+
|
|
19
|
+
parse_id3v2_tag unless no_tag_parsing
|
|
20
|
+
parse_id3v1_tag unless no_tag_parsing
|
|
21
|
+
read_audio_data unless no_tag_parsing
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# parses the id3v1 tag
|
|
25
|
+
def parse_id3v1_tag
|
|
26
|
+
length = @file.is_a?(File) ? @file.size : @file.length
|
|
27
|
+
if length > 128
|
|
28
|
+
@file.seek(-128, IO::SEEK_END)
|
|
29
|
+
@id3v1_tag = Id3v1Tag.build_from_file(@file) if Id3v1Tag.id3v1_tag?(@file)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@audio_end_index = @id3v1_tag.nil? ? @file.size : @file.size - Id3v1Tag::TAG_SIZE
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# parses the id3v2 tag
|
|
36
|
+
def parse_id3v2_tag
|
|
37
|
+
@id3v2_tag = Id3v2Tag.build_from_file(@file, @options) if Id3v2Tag.id3v2_tag?(@file)
|
|
38
|
+
@audio_start_index = @id3v2_tag.nil? ? 0 : @id3v2_tag.total_tag_size
|
|
39
|
+
|
|
40
|
+
@id3v2_tag&.add_size_tag_if_not_present(audio_size_without_id3v2_tag)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# removes the id3v1 tag
|
|
44
|
+
def remove_id3v1_tag
|
|
45
|
+
@id3v1_tag = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# creates the id3v1 tag. If a tag already exists, it must be removed first.
|
|
49
|
+
#
|
|
50
|
+
# @return [Id3v1Tag] the created Id3v1 tag
|
|
51
|
+
def create_id3v1_tag
|
|
52
|
+
raise Errors::Id3TagError, 'An ID3v1 tag already exists. Can\'t create a 2nd one.' unless @id3v1_tag.nil?
|
|
53
|
+
|
|
54
|
+
@id3v1_tag = Id3v1Tag.new
|
|
55
|
+
@id3v1_tag
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# removes the id3v1 tag
|
|
59
|
+
def remove_id3v2_tag
|
|
60
|
+
@id3v2_tag = nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# creates the id3v2.2 tag. If a tag already exists, it must be removed first.
|
|
64
|
+
#
|
|
65
|
+
# @return [Id3v22Tag, Id3v23Tag, Id3v24Tag] the created Id3v2.2 tag
|
|
66
|
+
def create_id3v2_2_tag
|
|
67
|
+
raise Errors::Id3TagError, 'An ID3v2.2 tag already exists. Can\'t create a 2nd one.' unless @id3v1_tag.nil?
|
|
68
|
+
|
|
69
|
+
@id3v2_tag = Id3v2Tag.build_for_version(2, @options)
|
|
70
|
+
@id3v2_tag
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# creates the id3v2.3 tag. If a tag already exists, it must be removed first.
|
|
74
|
+
#
|
|
75
|
+
# @return [Id3v22Tag, Id3v23Tag, Id3v24Tag] the created Id3v2.3 tag
|
|
76
|
+
def create_id3v2_3_tag
|
|
77
|
+
raise Errors::Id3TagError, 'An ID3v2.3 tag already exists. Can\'t create a 2nd one.' unless @id3v1_tag.nil?
|
|
78
|
+
|
|
79
|
+
@id3v2_tag = Id3v2Tag.build_for_version(3, @options)
|
|
80
|
+
@id3v2_tag
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# creates the id3v2.4 tag. If a tag already exists, it must be removed first.
|
|
84
|
+
#
|
|
85
|
+
# @return [Id3v22Tag, Id3v23Tag, Id3v24Tag] the created Id3v2.4 tag
|
|
86
|
+
def create_id3v2_4_tag
|
|
87
|
+
raise Errors::Id3TagError, 'An ID3v2.4 tag already exists. Can\'t create a 2nd one.' unless @id3v1_tag.nil?
|
|
88
|
+
|
|
89
|
+
@id3v2_tag = Id3v2Tag.build_for_version(4, @options)
|
|
90
|
+
@id3v2_tag
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# writes the audio file to the specified path
|
|
94
|
+
# Note: This path can be the same path as the path that was used to read the file
|
|
95
|
+
#
|
|
96
|
+
# @param path [String] the file where to write the modified file too
|
|
97
|
+
def write_audio_file(path)
|
|
98
|
+
out_file = File.open(path, 'w')
|
|
99
|
+
out_file.write(audio_file_to_bytes)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# creates a byte array represented as a String (str.bytes) of the modified file data
|
|
103
|
+
#
|
|
104
|
+
# @return [String] the byte array of the file represented as a String
|
|
105
|
+
def audio_file_to_bytes
|
|
106
|
+
@id3v2_tag&.add_size_tag_if_not_present(audio_size_without_id3v2_tag)
|
|
107
|
+
|
|
108
|
+
bytes = []
|
|
109
|
+
bytes << @id3v2_tag.to_bytes unless @id3v2_tag.nil?
|
|
110
|
+
bytes << read_audio_data
|
|
111
|
+
bytes << @id3v1_tag.to_bytes unless @id3v1_tag.nil?
|
|
112
|
+
|
|
113
|
+
bytes.inject([]) { |sum, x| sum + x.bytes }.pack('C*')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# reads the audio data part from the file
|
|
117
|
+
#
|
|
118
|
+
# @return [String] the byte array audio data part of the file represented as a String (str.bytes)
|
|
119
|
+
def read_audio_data
|
|
120
|
+
return @audio_data unless @audio_data.nil?
|
|
121
|
+
|
|
122
|
+
@file.seek(@audio_start_index)
|
|
123
|
+
@audio_data = @file.read(@audio_end_index - @audio_start_index)
|
|
124
|
+
@audio_data
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# returns the audio size without the id3v2 tag (note, if an id3v1 header is present, this size is included)
|
|
128
|
+
#
|
|
129
|
+
# @return [Integer] the size of the audio file without the id3v2 tag size
|
|
130
|
+
def audio_size_without_id3v2_tag
|
|
131
|
+
@audio_start_index - @file.size
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private :parse_id3v2_tag, :parse_id3v1_tag, :audio_size_without_id3v2_tag
|
|
135
|
+
end
|
|
136
|
+
end
|