mirror of
https://codeberg.org/unspeaker/perch.git
synced 2025-12-06 09:36:42 +01:00
wip: 3-way merge logic
This commit is contained in:
parent
d1889481b1
commit
44315dcc72
1 changed files with 100 additions and 48 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering};
|
use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering};
|
||||||
use byte_unit::{Byte, Unit::MB};
|
use byte_unit::{Byte, Unit::MB};
|
||||||
|
|
@ -75,7 +76,17 @@ impl Entry {
|
||||||
}
|
}
|
||||||
pub fn is_modified (&self) -> bool {
|
pub fn is_modified (&self) -> bool {
|
||||||
match &*self.info.read().unwrap() {
|
match &*self.info.read().unwrap() {
|
||||||
Metadata::Music { modified_tag, .. } => modified_tag.is_some(),
|
Metadata::Music { original_tag, modified_tag, .. } => match (
|
||||||
|
original_tag,
|
||||||
|
modified_tag,
|
||||||
|
) {
|
||||||
|
(Some(original), Some(modified)) => {
|
||||||
|
let original_items: HashSet<_> = original.items().collect();
|
||||||
|
original_items != modified.read().unwrap().items().collect()
|
||||||
|
},
|
||||||
|
(None, None) => false,
|
||||||
|
_ => true,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,24 +102,26 @@ impl PartialOrd for Entry {
|
||||||
|
|
||||||
pub enum Metadata {
|
pub enum Metadata {
|
||||||
Directory {
|
Directory {
|
||||||
hash_file: Option<()>,
|
hash_file: Option<()>,
|
||||||
catalog_file: Option<()>,
|
catalog_file: Option<()>,
|
||||||
artist_file: Option<()>,
|
artist_file: Option<()>,
|
||||||
release_file: Option<()>,
|
release_file: Option<()>,
|
||||||
},
|
},
|
||||||
Music {
|
Music {
|
||||||
invalid: bool,
|
invalid: bool,
|
||||||
hash: Arc<str>,
|
hash: Arc<str>,
|
||||||
size: Arc<str>,
|
size: Arc<str>,
|
||||||
|
/// The tag that was read from the file
|
||||||
original_tag: Option<Arc<Tag>>,
|
original_tag: Option<Arc<Tag>>,
|
||||||
|
/// The tag that will be written to the file
|
||||||
modified_tag: Option<Arc<RwLock<Tag>>>,
|
modified_tag: Option<Arc<RwLock<Tag>>>,
|
||||||
},
|
},
|
||||||
Image {
|
Image {
|
||||||
invalid: bool,
|
invalid: bool,
|
||||||
hash: Arc<str>,
|
hash: Arc<str>,
|
||||||
size: Arc<str>,
|
size: Arc<str>,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
author: Option<String>,
|
author: Option<String>,
|
||||||
},
|
},
|
||||||
Unknown {
|
Unknown {
|
||||||
hash: Arc<str>,
|
hash: Arc<str>,
|
||||||
|
|
@ -136,7 +149,7 @@ impl Metadata {
|
||||||
size: format!("{:#>8.2}", size).into(),
|
size: format!("{:#>8.2}", size).into(),
|
||||||
invalid: false,
|
invalid: false,
|
||||||
original_tag: tag.map(|t|t.clone().into()),
|
original_tag: tag.map(|t|t.clone().into()),
|
||||||
modified_tag: None,
|
modified_tag: tag.map(|t|Arc::new(t.clone().into())),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Self::new_fallback(path)
|
Self::new_fallback(path)
|
||||||
|
|
@ -226,49 +239,88 @@ macro_rules! music_tag_field {
|
||||||
}
|
}
|
||||||
/// Set or delete the metadata value.
|
/// Set or delete the metadata value.
|
||||||
/// Return whether the changes should be recounted.
|
/// Return whether the changes should be recounted.
|
||||||
pub fn $set (&mut self, raw_value: Option<&str>) -> bool {
|
pub fn $set (&mut self, value: Option<&str>) -> bool {
|
||||||
let parse = $parse;
|
let parse = $parse;
|
||||||
if let &mut Metadata::Music { ref mut modified_tag, .. } = self {
|
match self {
|
||||||
//let write = $write;
|
|
||||||
if let Some(raw_value) = raw_value {
|
&mut Metadata::Music {
|
||||||
// Set value
|
original_tag: Some(ref original), modified_tag: Some(ref modified), ..
|
||||||
if let Ok(parsed_value) = parse(raw_value) {
|
} => if let Some(value) = value {
|
||||||
match &modified_tag {
|
// set new value
|
||||||
Some(new_tag) => {
|
let value = parse(value).unwrap();
|
||||||
// add entry to modified_tag
|
let changed = original.$get() != Some(value);
|
||||||
new_tag.write().unwrap().$set(parsed_value);
|
modified.write().unwrap().$set(value);
|
||||||
true
|
changed
|
||||||
},
|
} else {
|
||||||
None => {
|
let modified = modified.write().unwrap();
|
||||||
// first entry creates modified_tag
|
if let Some(value) = modified.$get() {
|
||||||
let mut new_tag = Tag::new(TagType::Id3v2); // FIXME other types
|
// delete modified value
|
||||||
new_tag.$set(parsed_value);
|
modified.$del();
|
||||||
*modified_tag = Some(Arc::new(RwLock::new(new_tag)));
|
true
|
||||||
true
|
} else if let Some(value) = original.$get() {
|
||||||
},
|
// set to original value
|
||||||
}
|
modified.$set(value);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
&mut Metadata::Music {
|
||||||
|
original_tag: Some(ref original), ref mut modified_tag, ..
|
||||||
|
} => if let Some(input_value) = value {
|
||||||
|
let mut new_tag = Tag::new(TagType::Id3v2); // FIXME other types
|
||||||
|
new_tag.$set(input_value);
|
||||||
|
*modified_tag = Some(Arc::new(RwLock::new(new_tag)));
|
||||||
|
true
|
||||||
|
} else if let Some(original_value) = original.$get() {
|
||||||
|
// set to original value
|
||||||
|
let mut new_tag = Tag::new(TagType::Id3v2); // FIXME other types
|
||||||
|
new_tag.$set(original_value);
|
||||||
|
*modified_tag = Some(Arc::new(RwLock::new(new_tag)));
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
|
||||||
|
&mut Metadata::Music {
|
||||||
|
original_tag: None, modified_tag: Some(ref modified), ..
|
||||||
|
} => if let Some(value) = value {
|
||||||
|
// set new value
|
||||||
|
let value = parse(value).unwrap();
|
||||||
|
let modified = modified.write().unwrap();
|
||||||
|
if modified.$get() != Some(value) {
|
||||||
|
// set modified value
|
||||||
|
modified.$set(value);
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Delete value
|
let modified = modified.write().unwrap();
|
||||||
match &modified_tag {
|
if modified.$get().is_some() {
|
||||||
Some(new_tag) => {
|
// remove modified value
|
||||||
// remove entry from modified_tag
|
modified.$del();
|
||||||
new_tag.write().unwrap().$del();
|
true
|
||||||
if new_tag.read().unwrap().item_count() <= 1 {
|
} else {
|
||||||
// removing last entry removes modified_tag
|
false
|
||||||
*modified_tag = None;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
&mut Metadata::Music {
|
||||||
|
original_tag: None, ref mut modified_tag, ..
|
||||||
|
} => if let Some(value) = value {
|
||||||
|
let mut new_tag = Tag::new(TagType::Id3v2); // FIXME other types
|
||||||
|
new_tag.$set(value);
|
||||||
|
*modified_tag = Some(Arc::new(RwLock::new(new_tag)));
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +340,7 @@ generated_field!(size = |self|match self {
|
||||||
});
|
});
|
||||||
music_tag_field!(artist set_artist remove_artist ItemKey::TrackArtist;
|
music_tag_field!(artist set_artist remove_artist ItemKey::TrackArtist;
|
||||||
write = |value: Cow<str>|value.into();
|
write = |value: Cow<str>|value.into();
|
||||||
parse = |value: &str|Ok::<String, ()>(value.trim().into()););
|
parse = |value: &str|Ok::<String, ()>(value.trim()););
|
||||||
music_tag_field!(year set_year remove_year ItemKey::Year;
|
music_tag_field!(year set_year remove_year ItemKey::Year;
|
||||||
write = |value: u32|format!("{value}").into();
|
write = |value: u32|format!("{value}").into();
|
||||||
parse = |value: &str|value.trim().parse::<u32>(););
|
parse = |value: &str|value.trim().parse::<u32>(););
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue