Unquoted album tracks: the name starts at the track number
"A Strange Light from the East - Eastern Influenced Western Music
(1965-72) - CD2 - 07 - Rascals - Sattva.mp3 (1/43)": unquotedName cut at
the last " - " ("Sattva.mp3"), leaving track number and artist in the
subject, so every track was a release (85665085, 85665050). With a
" - NN - " track or part number the name starts there ("07 - Rascals -
Sattva.mp3"), the rest names the album and disc. Both implementations;
tests; fixtures identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e0a0d0d520
commit
8d400822bd
4 files changed
+29
-2
No files matched your search
+17
-1
@@ -259,6 +259,20 @@ fn has_extension(s: &str) -> bool {
|
||||
s[..dot].chars().last().is_some_and(|c| c != '.' && !js::is_space(c))
|
||||
}
|
||||
|
||||
/// The first / - \d{1,3} - / in `text`: the index of its " - ".
|
||||
fn first_track(text: &str) -> Option<usize> {
|
||||
let b = text.as_bytes();
|
||||
let mut from = 0;
|
||||
while let Some(i) = text[from..].find(" - ").map(|i| i + from) {
|
||||
let digits = b[i + 3..].iter().take_while(|c| c.is_ascii_digit()).count();
|
||||
if (1..=3).contains(&digits) && b[i + 3 + digits..].starts_with(b" - ") {
|
||||
return Some(i);
|
||||
}
|
||||
from = i + 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// unquotedName (lib/headers/subject.ts): the file name of a subject without a quoted one, from the text before its counter.
|
||||
pub fn unquoted_name(before_counter: &str) -> Option<String> {
|
||||
let mut text = before_counter.trim_end_matches(js::is_space);
|
||||
@@ -300,7 +314,8 @@ pub fn unquoted_name(before_counter: &str) -> Option<String> {
|
||||
}
|
||||
if has_extension(text) {
|
||||
let bracket = text.rfind("] ").map_or(0, |i| i + 2);
|
||||
let dash = text.rfind(" - ").map_or(0, |i| i + 3);
|
||||
// A track or part number (/ - \d{1,3} - /): the name starts there; else after the last " - ".
|
||||
let dash = first_track(text).or_else(|| text.rfind(" - ")).map_or(0, |i| i + 3);
|
||||
let name = js::trim(&text[bracket.max(dash)..]);
|
||||
return (!name.is_empty() && has_extension(name)).then(|| name.to_string());
|
||||
}
|
||||
@@ -870,6 +885,7 @@ mod unquoted_tests {
|
||||
("New_Super_Mario_Bros._[Keygen].exe ", Some("New_Super_Mario_Bros._[Keygen].exe")),
|
||||
("Emily_18_-_Bed.part01.rar Emily 18 bed video FULL NUDE ", Some("Emily_18_-_Bed.part01.rar")),
|
||||
("[33/117] 674a37548b09.dat ", Some("674a37548b09.dat")),
|
||||
("A Strange Light from the East - Eastern Influenced Western Music (1965-72) - CD2 - 07 - Rascals - Sattva.mp3 ", Some("07 - Rascals - Sattva.mp3")),
|
||||
("pal! [Mivina high(1).wmv\" yEnc] ", Some("Mivina high(1).wmv")),
|
||||
("[03/21 Geroellheimer - S03E16.part01.rar\" yEnc ", Some("Geroellheimer - S03E16.part01.rar")),
|
||||
("[7w] - 9BbEV2MrTi59GBTEFlVrssBrXNwXf2SK9cQEeDjg yEnc ", None),
|
||||
|
||||
@@ -48,7 +48,10 @@ export function unquotedName(beforeCounter: string): string | null {
|
||||
}
|
||||
if (EXTENSION.test(text)) {
|
||||
const bracket = text.lastIndexOf('] ')
|
||||
const dash = text.lastIndexOf(' - ')
|
||||
// A track or part number ("Album - CD2 - 07 - Artist - Title.mp3"): the name starts there, so the rest
|
||||
// is the album, the same for every track (LOG.md 2026-10-11 (10)); else after the last " - ".
|
||||
const track = / - \d{1,3} - /.exec(text)
|
||||
const dash = track ? track.index : text.lastIndexOf(' - ')
|
||||
const cut = Math.max(bracket === -1 ? 0 : bracket + 2, dash === -1 ? 0 : dash + 3)
|
||||
const name = text.slice(cut).trim()
|
||||
return name && EXTENSION.test(name) ? name : null
|
||||
|
||||
@@ -53,6 +53,7 @@ test.group('subject / parseSubject', () => {
|
||||
['New_Super_Mario_Bros._[Keygen].exe (1/2)', 'New_Super_Mario_Bros._[Keygen].exe', 1, 2],
|
||||
['Emily_18_-_Bed.part01.rar Emily 18 bed video FULL NUDE (01/24)', 'Emily_18_-_Bed.part01.rar', 1, 24],
|
||||
['[33/117] 674a37548b09.dat (1/1)', '674a37548b09.dat', 1, 1, 33],
|
||||
['A Strange Light from the East - Eastern Influenced Western Music (1965-72) - CD2 - 07 - Rascals - Sattva.mp3 (1/43)', '07 - Rascals - Sattva.mp3', 1, 43],
|
||||
["pal! [Mivina high(1).wmv\" yEnc] (323/349)", 'Mivina high(1).wmv', 323, 349],
|
||||
['[03/21 Geroellheimer - S03E16.part01.rar" yEnc (1/50)', 'Geroellheimer - S03E16.part01.rar', 1, 50],
|
||||
]
|
||||
|
||||
@@ -187,6 +187,13 @@ test.group('release / par2 names', () => {
|
||||
assert.isFalse(randomPoster('w.merklein@freenet.de (muffin)'))
|
||||
})
|
||||
|
||||
test('album tracks with unquoted names are one release per disc', async ({ assert }) => {
|
||||
const { parseSubject } = await import('#lib/headers/index')
|
||||
const id = (subject: string) => releaseIdentity({ poster: 'Hannah_Qe@hotmail.com (Spidey)', subject: subject.replace(/ \(\d+\/\d+\)$/, ''), name: parseSubject(subject)!.name, weak: false })!
|
||||
const album = 'A Strange Light from the East - Eastern Influenced Western Music (1965-72) - CD2'
|
||||
assert.equal(id(`${album} - 07 - Rascals - Sattva.mp3 (1/43)`).key, id(`${album} - 08 - Incredible String Band - Koeeoaddi There.mp3 (1/47)`).key)
|
||||
})
|
||||
|
||||
test('image sets: sizes in brackets and one-word set names', ({ assert }) => {
|
||||
const id = (subject: string, name: string) => releaseIdentity({ poster: 'p', subject, name, weak: false })!
|
||||
assert.equal(id('Aletta Ocean - "100628-035.jpg" yEnc [347K]', '100628-035.jpg').key, id('Aletta Ocean - "100628-036.jpg" yEnc [298K]', '100628-036.jpg').key)
|
||||
|
||||
Reference in new issue
Block a user