DVD Integration

This commit is contained in:
2026-03-06 11:21:25 +00:00
parent 3abb53fb8e
commit e1a87af16a
20 changed files with 2900 additions and 697 deletions
+130 -1
View File
@@ -20,7 +20,42 @@ function flattenDevices(nodes, acc = []) {
}
function buildSignature(info) {
return `${info.path || ''}|${info.discLabel || ''}|${info.label || ''}|${info.model || ''}|${info.mountpoint || ''}|${info.fstype || ''}`;
return `${info.path || ''}|${info.discLabel || ''}|${info.label || ''}|${info.model || ''}|${info.mountpoint || ''}|${info.fstype || ''}|${info.mediaProfile || ''}`;
}
function normalizeMediaProfile(rawValue) {
const value = String(rawValue || '').trim().toLowerCase();
if (!value) {
return null;
}
if (value === 'bluray' || value === 'blu-ray' || value === 'bd' || value === 'bdmv') {
return 'bluray';
}
if (value === 'dvd') {
return 'dvd';
}
if (value === 'disc' || value === 'other' || value === 'sonstiges' || value === 'cd') {
return 'other';
}
return null;
}
function inferMediaProfileFromTextParts(parts) {
const markerText = (parts || [])
.map((value) => String(value || '').trim().toLowerCase())
.filter(Boolean)
.join(' ');
if (!markerText) {
return null;
}
if (/(^|[\s_-])bdmv($|[\s_-])|blu[\s-]?ray|bd-rom|bd-r|bd-re/.test(markerText)) {
return 'bluray';
}
if (/(^|[\s_-])video_ts($|[\s_-])|dvd/.test(markerText)) {
return 'dvd';
}
return null;
}
class DiskDetectionService extends EventEmitter {
@@ -265,6 +300,14 @@ class DiskDetectionService extends EventEmitter {
const details = await this.getBlockDeviceInfo();
const match = details.find((entry) => entry.path === devicePath || `/dev/${entry.name}` === devicePath) || {};
const mediaProfile = await this.inferMediaProfile(devicePath, {
discLabel,
label: match.label,
model: match.model,
fstype: match.fstype,
mountpoint: match.mountpoint
});
const detected = {
mode: 'explicit',
path: devicePath,
@@ -274,6 +317,7 @@ class DiskDetectionService extends EventEmitter {
discLabel: discLabel || null,
mountpoint: match.mountpoint || null,
fstype: match.fstype || null,
mediaProfile: mediaProfile || null,
index: this.guessDiscIndex(match.name || devicePath)
};
logger.debug('detect:explicit:success', { detected });
@@ -304,6 +348,14 @@ class DiskDetectionService extends EventEmitter {
}
const discLabel = await this.getDiscLabel(path);
const mediaProfile = await this.inferMediaProfile(path, {
discLabel,
label: item.label,
model: item.model,
fstype: item.fstype,
mountpoint: item.mountpoint
});
const detected = {
mode: 'auto',
path,
@@ -313,6 +365,7 @@ class DiskDetectionService extends EventEmitter {
discLabel: discLabel || null,
mountpoint: item.mountpoint || null,
fstype: item.fstype || null,
mediaProfile: mediaProfile || null,
index: this.guessDiscIndex(item.name)
};
logger.debug('detect:auto:success', { detected });
@@ -372,6 +425,82 @@ class DiskDetectionService extends EventEmitter {
}
}
async inferMediaProfile(devicePath, hints = {}) {
const explicit = normalizeMediaProfile(hints?.mediaProfile);
if (explicit) {
return explicit;
}
const hinted = inferMediaProfileFromTextParts([
hints?.discLabel,
hints?.label,
hints?.fstype
]);
if (hinted) {
return hinted;
}
const mountpoint = String(hints?.mountpoint || '').trim();
if (mountpoint) {
try {
if (fs.existsSync(`${mountpoint}/BDMV`)) {
return 'bluray';
}
} catch (_error) {
// ignore fs errors
}
try {
if (fs.existsSync(`${mountpoint}/VIDEO_TS`)) {
return 'dvd';
}
} catch (_error) {
// ignore fs errors
}
}
try {
const { stdout } = await execFileAsync('blkid', ['-o', 'export', devicePath]);
const payload = {};
for (const line of String(stdout || '').split(/\r?\n/)) {
const idx = line.indexOf('=');
if (idx <= 0) {
continue;
}
const key = String(line.slice(0, idx)).trim().toUpperCase();
const value = String(line.slice(idx + 1)).trim();
if (!key) {
continue;
}
payload[key] = value;
}
const byBlkidMarker = inferMediaProfileFromTextParts([
payload.LABEL,
payload.TYPE,
payload.VERSION
]);
if (byBlkidMarker) {
return byBlkidMarker;
}
const type = String(payload.TYPE || '').trim().toLowerCase();
if (type === 'udf') {
const version = Number.parseFloat(String(payload.VERSION || '').replace(',', '.'));
if (Number.isFinite(version)) {
return version >= 2 ? 'bluray' : 'dvd';
}
return 'dvd';
}
} catch (error) {
logger.debug('infer-media-profile:blkid-failed', {
devicePath,
error: errorToMeta(error)
});
}
return null;
}
guessDiscIndex(name) {
if (!name) {
return 0;