{"id":16587262,"url":"https://github.com/saecki/mp4ameta","last_synced_at":"2025-03-21T13:30:43.942Z","repository":{"id":48601474,"uuid":"251662934","full_name":"saecki/mp4ameta","owner":"saecki","description":"A library for reading and writing iTunes style MPEG-4 audio metadata","archived":false,"fork":false,"pushed_at":"2025-03-10T21:56:08.000Z","size":1314,"stargazers_count":36,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-16T15:15:38.472Z","etag":null,"topics":["m4a","m4a-tags","m4b","metadata","mpeg-audio","parser","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saecki.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-31T16:25:39.000Z","updated_at":"2025-02-25T16:02:44.000Z","dependencies_parsed_at":"2024-02-05T09:31:00.921Z","dependency_job_id":"551e4567-307d-4e56-a9d2-7b67e76d8d03","html_url":"https://github.com/saecki/mp4ameta","commit_stats":null,"previous_names":["saecki/rust-mp4ameta"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saecki%2Fmp4ameta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saecki%2Fmp4ameta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saecki%2Fmp4ameta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saecki%2Fmp4ameta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saecki","download_url":"https://codeload.github.com/saecki/mp4ameta/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244806047,"owners_count":20513368,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["m4a","m4a-tags","m4b","metadata","mpeg-audio","parser","rust"],"created_at":"2024-10-11T22:53:41.518Z","updated_at":"2025-03-21T13:30:43.936Z","avatar_url":"https://github.com/saecki.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mp4ameta\n[![Build](https://github.com/Saecki/mp4ameta/actions/workflows/build.yml/badge.svg)](https://github.com/Saecki/mp4ameta/actions/workflows/build.yml)\n[![Crate](https://img.shields.io/crates/v/mp4ameta.svg)](https://crates.io/crates/mp4ameta)\n[![Documentation](https://img.shields.io/docsrs/mp4ameta?label=docs.rs)](https://docs.rs/mp4ameta)\n![License](https://img.shields.io/crates/l/mp4ameta)\n![LOC](https://tokei.rs/b1/github/saecki/mp4ameta?category=code)\n\nA library for reading and writing iTunes style MPEG-4 audio metadata.\nMost commonly this kind of metadata is found inside `m4a` or `m4b` files but basically any `mp4` container supports it.\n\n## Examples\n\n### The Easy Way\n```rs\nlet mut tag = mp4ameta::Tag::read_from_path(\"music.m4a\").unwrap();\n\nprintln!(\"{}\", tag.artist().unwrap());\n\ntag.set_artist(\"artist\");\ntag.write_to_path(\"music.m4a\").unwrap();\n```\n\n### The Hard Way\n```rs\nuse mp4ameta::{Data, Fourcc, Tag};\n\nlet mut tag = Tag::read_from_path(\"music.m4a\").unwrap();\nlet artist_ident = Fourcc(*b\"\\xa9ART\");\n\nlet artist = tag.strings_of(\u0026artist_ident).next().unwrap();\nprintln!(\"{}\", artist);\n\ntag.set_data(artist_ident, Data::Utf8(\"artist\".to_owned()));\ntag.write_to_path(\"music.m4a\").unwrap();\n```\n\n### Using Freeform Identifiers\n```rs\nuse mp4ameta::{Data, FreeformIdent, Tag};\n\nlet mut tag = Tag::read_from_path(\"music.m4a\").unwrap();\nlet isrc_ident = FreeformIdent::new_static(\"com.apple.iTunes\", \"ISRC\");\n\nlet isrc = tag.strings_of(\u0026isrc_ident).next().unwrap();\nprintln!(\"{}\", isrc);\n\ntag.set_data(isrc_ident, Data::Utf8(\"isrc\".to_owned()));\ntag.write_to_path(\"music.m4a\").unwrap();\n```\n\n### Chapters\nThere are two ways of storing chapters in mp4 files.\nThey can either be stored inside a chapter list, or a chapter track.\n```rs\nuse mp4ameta::{Chapter, Tag};\nuse std::time::Duration;\n\nlet mut tag = Tag::read_from_path(\"audiobook.m4b\").unwrap();\n\nfor chapter in tag.chapter_track() {\n    let mins = chapter.start.as_secs() / 60;\n    let secs = chapter.start.as_secs() % 60;\n    println!(\"{mins:02}:{secs:02} {}\", chapter.title);\n}\ntag.chapter_track_mut().clear();\n\ntag.chapter_list_mut().extend([\n    Chapter::new(Duration::ZERO, \"first chapter\"),\n    Chapter::new(Duration::from_secs(3 * 60 + 42), \"second chapter\"),\n    Chapter::new(Duration::from_secs(7 * 60 + 13), \"third chapter\"),\n]);\n\ntag.write_to_path(\"audiobook.m4b\").unwrap();\n```\n\n### Read and Write Configurations\nRead only the data that is relevant for your usecase.\nAnd (over)write only the data that you want to edit.\n\nBy default all data is read and written.\n```rs\nuse mp4ameta::{ChplTimescale, ReadConfig, Tag, WriteConfig};\n\n// Only read the metadata item list, not chapters or audio information\nlet read_cfg = ReadConfig {\n    read_meta_items: true,\n    read_image_data: false,\n    read_chapter_list: false,\n    read_chapter_track: false,\n    read_audio_info: false,\n    chpl_timescale: ChplTimescale::DEFAULT,\n};\nlet mut tag = Tag::read_with_path(\"music.m4a\", \u0026read_cfg).unwrap();\n\nprintln!(\"{tag}\");\n\ntag.clear_meta_items();\n\n// Only overwrite the metadata item list, leave chapters intact\nlet write_cfg = WriteConfig {\n    write_meta_items: true,\n    write_chapter_list: false,\n    write_chapter_track: false,\n    chpl_timescale: ChplTimescale::DEFAULT,\n};\ntag.write_with_path(\"music.m4a\", \u0026write_cfg).unwrap();\n```\n\n## Useful Links\n- QuickTime spec\n    - [Overview of QTFF](https://developer.apple.com/documentation/quicktime-file-format)\n    - [Movie atoms](https://developer.apple.com/documentation/quicktime-file-format/movie_atoms)\n    - [User data atoms](https://developer.apple.com/documentation/quicktime-file-format/user_data_atoms)\n- [MultimediaWiki QuickTime container](https://wiki.multimedia.cx/index.php/QuickTime_container)\n- [AtomicParsley docs](http://atomicparsley.sourceforge.net/mpeg-4files.html)\n- [Mutagen docs](https://mutagen.readthedocs.io/en/latest/api/mp4.html)\n- [Hydrogen audio tag mapping](https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping)\n- [MusicBrainz Picard tag mapping](https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html)\n- [Filetype list](https://ftyps.com/)\n\n## Testing\n__Run all tests:__\u003cbr/\u003e\n`cargo test`\n\n__Test this library on your collection:__\u003cbr/\u003e\n`cargo test -- --nocapture collection \u003cpath\u003e`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaecki%2Fmp4ameta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaecki%2Fmp4ameta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaecki%2Fmp4ameta/lists"}