summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock184
-rw-r--r--Cargo.toml10
-rw-r--r--default.nix18
-rw-r--r--src/main.rs169
5 files changed, 382 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..9c38170
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,184 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "lofty"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cb2b21027aa98f860de475b3ee8b10f36df689121b5752efeb7a64bec1f4d45"
+dependencies = [
+ "base64",
+ "byteorder",
+ "flate2",
+ "lofty_attr",
+ "log",
+ "ogg_pager",
+ "once_cell",
+ "paste",
+]
+
+[[package]]
+name = "lofty_attr"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9482ad911db377f8362c658aff576aac289c84cf5c25ca058e2c49d9bc3301dc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "log"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "ogg-tagger"
+version = "0.1.0"
+dependencies = [
+ "lofty",
+ "regex",
+]
+
+[[package]]
+name = "ogg_pager"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d218a406e5de88e1c492d0162d569916f7436efe851ba5cc40a4bf4fa97cb40"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+
+[[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+
+[[package]]
+name = "syn"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..6139a41
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "ogg-tagger"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+lofty = "0.13.0"
+regex = "1.8.3" \ No newline at end of file
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..c7aacee
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,18 @@
+{ pkgs ? import <nixpkgs> { } }:
+
+let
+ manifest = (pkgs.lib.importTOML ./Cargo.toml).package;
+in pkgs.rustPlatform.buildRustPackage rec {
+ pname = manifest.name;
+ version = manifest.version;
+
+ cargoLock.lockFile = ./Cargo.lock;
+ src = pkgs.lib.cleanSource ./.;
+
+ meta = with pkgs.lib; {
+ description = "A fast line-oriented regex search tool, similar to ag and ack";
+ homepage = "https://github.com/BurntSushi/ripgrep";
+ license = licenses.gpl3;
+ maintainers = [ "jptrzy" ];
+ };
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..2bf1274
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,169 @@
+use std::{fs::{self, File}, path::Path, io::{Error, BufReader, Read}, fmt::format, os::fd::IntoRawFd};
+
+use lofty::{Probe, TaggedFileExt, LoftyError, TagExt, Tag, Picture, Accessor, PictureType};
+
+/*
+ Title
+ Artist - Title
+ Artist - Album - Title
+ Artist - Album - Nr - Title
+ Artist - Album - Nr - Max Nr - Title
+ */
+
+struct InnerTag {
+ title: String,
+ artist: Option<String>,
+ album: Option<String>,
+ track: Option<u32>,
+}
+
+impl InnerTag {
+ pub fn empty() -> InnerTag {
+ InnerTag {title: "".into(), artist: None, album: None, track: None}
+ }
+
+ pub fn from(name: &str) -> Result<InnerTag, Error>{
+ let mut inner_tag: InnerTag = InnerTag::empty();
+
+ let mut tags: Vec<String> = Vec::new();
+
+ { // TODO make it faster and cleaner
+ let mut text: String = "".into();
+ let mut connected = false;
+
+ for s in name.split("-") {
+ if text == "" {
+ text = s.into();
+ } else {
+ if s == "" {
+ connected = true;
+ text += "-";
+ } else if connected {
+ text += s;
+ connected = false;
+ } else {
+ tags.push(text);
+ text = s.into();
+ }
+ }
+ }
+
+ tags.push(text);
+ }
+
+ match tags.len() {
+ 1 => {
+ inner_tag.title = tags.remove(0);
+ },
+ 2 => {
+ inner_tag.artist = Some(tags.remove(0));
+ inner_tag.title = tags.remove(0);
+ },
+ 3 => {
+ inner_tag.artist = Some(tags.remove(0));
+ inner_tag.album = Some(tags.remove(0));
+ inner_tag.title = tags.remove(0);
+ },
+ 4 => {
+ inner_tag.artist = Some(tags.remove(0));
+ inner_tag.album = Some(tags.remove(0));
+ inner_tag.track = Some(tags.remove(0).parse().unwrap());
+ inner_tag.title = tags.remove(0);
+ },
+ 5 => {
+ inner_tag.artist = Some(tags.remove(0));
+ inner_tag.album = Some(tags.remove(0));
+ inner_tag.track = Some(tags.remove(0).parse().unwrap());
+ inner_tag.title = tags.remove(1);
+ },
+ _ => panic!("FUCK to many tags {}", tags.len())
+ }
+
+ return Ok(inner_tag);
+ }
+}
+
+fn truncate(s: &str, min_chars: usize, max_chars: usize) -> &str {
+ let e = match s.char_indices().nth(min_chars) {
+ None => s,
+ Some((idx, _)) => &s[idx..],
+ };
+
+ if max_chars < min_chars {
+ return "";
+ }
+
+ return match e.char_indices().nth(max_chars - min_chars) {
+ None => e,
+ Some((idx, _)) => &e[..idx],
+ }
+}
+
+fn tag_ogg_file(path: &Path) -> Result<(), LoftyError> {
+ let mut tagged_file = Probe::open(path)
+ .expect("ERROR: Bad path provided!")
+ .read()?;
+
+ let tag = match tagged_file.primary_tag_mut() {
+ Some(primary_tag) => primary_tag,
+ None => {
+ if let Some(first_tag) = tagged_file.first_tag_mut() {
+ first_tag
+ } else {
+ let tag_type = tagged_file.primary_tag_type();
+
+ eprintln!("WARN: No tags found, creating a new tag of type `{tag_type:?}`");
+ tagged_file.insert_tag(Tag::new(tag_type));
+
+ tagged_file.primary_tag_mut().unwrap()
+ }
+ },
+ };
+
+ let path_without_ext = path.with_extension("");
+ let name = path_without_ext.file_name().unwrap().to_str().unwrap();
+ let inner_tag = InnerTag::from(name).unwrap();
+
+ tag.clear();
+ tag.set_title(inner_tag.title);
+ tag.set_artist(inner_tag.artist.unwrap_or("".into()));
+ tag.set_album(inner_tag.album.unwrap_or("".into()));
+ if let Some(track) = inner_tag.track {
+ tag.set_track(track);
+ }
+
+ if let Some(album) = tag.album() {
+ if album != "" {
+ let image_path = path.parent().unwrap().join(format!(".cover/{}/{}.jpg", tag.artist().unwrap(), album));
+
+ if image_path.exists() {
+ let image_file = &mut File::open(image_path.clone()).unwrap();
+
+ let mut picture = Picture::from_reader(image_file).unwrap();
+ picture.set_pic_type(PictureType::CoverFront);
+
+ tag.set_picture(0, picture)
+ } else {
+ println!("⚠️ Can't found image {}", image_path.to_str().unwrap());
+ }
+ }
+ }
+
+
+ tag.save_to_path(path).expect("ERROR: Can't save ogg file");
+
+ println!("✅ {}", name);
+
+ return Ok(());
+}
+
+fn main() {
+ let music_dir = fs::read_dir("/home/jp3/Music").unwrap();
+
+ for path in music_dir {
+ // println!("Name: {}", path.unwrap().file_name().to_str().unwrap())
+ if path.as_ref().unwrap().file_type().unwrap().is_file() {
+ tag_ogg_file(path.unwrap().path().as_path());
+ }
+ }
+} \ No newline at end of file
Software created with 💖