mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-27 21:30:23 +02:00
feat(metadata): edit release tags and render UPC barcodes
This commit is contained in:
@@ -31,6 +31,10 @@ Map<String, dynamic> normalizeScannedAudioMetadata(
|
||||
normalized['total_discs'] = firstValue('total_discs', 'totalDiscs');
|
||||
normalized['bit_depth'] = firstValue('bit_depth', 'bitDepth');
|
||||
normalized['sample_rate'] = firstValue('sample_rate', 'sampleRate');
|
||||
normalized['album_type'] = firstValue('album_type', 'albumType');
|
||||
normalized['upc'] = firstValue('upc', 'barcode');
|
||||
normalized['comment'] = metadata['comment'];
|
||||
normalized['explicit'] = metadata['explicit'];
|
||||
normalized['audio_codec'] =
|
||||
firstValue('audio_codec', 'audioCodec') ?? metadata['format'];
|
||||
return normalized;
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
class RetailBarcodeData {
|
||||
final String value;
|
||||
final String symbology;
|
||||
final String modules;
|
||||
final int quietZoneModules;
|
||||
|
||||
const RetailBarcodeData({
|
||||
required this.value,
|
||||
required this.symbology,
|
||||
required this.modules,
|
||||
required this.quietZoneModules,
|
||||
});
|
||||
}
|
||||
|
||||
const _eanLeftOdd = <String>[
|
||||
'0001101',
|
||||
'0011001',
|
||||
'0010011',
|
||||
'0111101',
|
||||
'0100011',
|
||||
'0110001',
|
||||
'0101111',
|
||||
'0111011',
|
||||
'0110111',
|
||||
'0001011',
|
||||
];
|
||||
|
||||
const _eanLeftEven = <String>[
|
||||
'0100111',
|
||||
'0110011',
|
||||
'0011011',
|
||||
'0100001',
|
||||
'0011101',
|
||||
'0111001',
|
||||
'0000101',
|
||||
'0010001',
|
||||
'0001001',
|
||||
'0010111',
|
||||
];
|
||||
|
||||
const _eanRight = <String>[
|
||||
'1110010',
|
||||
'1100110',
|
||||
'1101100',
|
||||
'1000010',
|
||||
'1011100',
|
||||
'1001110',
|
||||
'1010000',
|
||||
'1000100',
|
||||
'1001000',
|
||||
'1110100',
|
||||
];
|
||||
|
||||
const _ean13Parity = <String>[
|
||||
'LLLLLL',
|
||||
'LLGLGG',
|
||||
'LLGGLG',
|
||||
'LLGGGL',
|
||||
'LGLLGG',
|
||||
'LGGLLG',
|
||||
'LGGGLL',
|
||||
'LGLGLG',
|
||||
'LGLGGL',
|
||||
'LGGLGL',
|
||||
];
|
||||
|
||||
// Code 128 module widths, including start/check/stop symbols. It is used only
|
||||
// as an exact-value fallback when a numeric identifier is not a valid UPC-A or
|
||||
// EAN-13. Valid retail identifiers always use their native symbology.
|
||||
const _code128Patterns = <String>[
|
||||
'212222',
|
||||
'222122',
|
||||
'222221',
|
||||
'121223',
|
||||
'121322',
|
||||
'131222',
|
||||
'122213',
|
||||
'122312',
|
||||
'132212',
|
||||
'221213',
|
||||
'221312',
|
||||
'231212',
|
||||
'112232',
|
||||
'122132',
|
||||
'122231',
|
||||
'113222',
|
||||
'123122',
|
||||
'123221',
|
||||
'223211',
|
||||
'221132',
|
||||
'221231',
|
||||
'213212',
|
||||
'223112',
|
||||
'312131',
|
||||
'311222',
|
||||
'321122',
|
||||
'321221',
|
||||
'312212',
|
||||
'322112',
|
||||
'322211',
|
||||
'212123',
|
||||
'212321',
|
||||
'232121',
|
||||
'111323',
|
||||
'131123',
|
||||
'131321',
|
||||
'112313',
|
||||
'132113',
|
||||
'132311',
|
||||
'211313',
|
||||
'231113',
|
||||
'231311',
|
||||
'112133',
|
||||
'112331',
|
||||
'132131',
|
||||
'113123',
|
||||
'113321',
|
||||
'133121',
|
||||
'313121',
|
||||
'211331',
|
||||
'231131',
|
||||
'213113',
|
||||
'213311',
|
||||
'213131',
|
||||
'311123',
|
||||
'311321',
|
||||
'331121',
|
||||
'312113',
|
||||
'312311',
|
||||
'332111',
|
||||
'314111',
|
||||
'221411',
|
||||
'431111',
|
||||
'111224',
|
||||
'111422',
|
||||
'121124',
|
||||
'121421',
|
||||
'141122',
|
||||
'141221',
|
||||
'112214',
|
||||
'112412',
|
||||
'122114',
|
||||
'122411',
|
||||
'142112',
|
||||
'142211',
|
||||
'241211',
|
||||
'221114',
|
||||
'413111',
|
||||
'241112',
|
||||
'134111',
|
||||
'111242',
|
||||
'121142',
|
||||
'121241',
|
||||
'114212',
|
||||
'124112',
|
||||
'124211',
|
||||
'411212',
|
||||
'421112',
|
||||
'421211',
|
||||
'212141',
|
||||
'214121',
|
||||
'412121',
|
||||
'111143',
|
||||
'111341',
|
||||
'131141',
|
||||
'114113',
|
||||
'114311',
|
||||
'411113',
|
||||
'411311',
|
||||
'113141',
|
||||
'114131',
|
||||
'311141',
|
||||
'411131',
|
||||
'211412',
|
||||
'211214',
|
||||
'211232',
|
||||
'2331112',
|
||||
];
|
||||
|
||||
RetailBarcodeData? encodeRetailBarcode(String rawValue) {
|
||||
final value = rawValue.replaceAll(RegExp(r'[\s-]+'), '');
|
||||
if (value.isEmpty || !RegExp(r'^\d+$').hasMatch(value)) return null;
|
||||
|
||||
if (value.length == 12 && hasValidGtinCheckDigit(value)) {
|
||||
return RetailBarcodeData(
|
||||
value: value,
|
||||
symbology: 'UPC-A',
|
||||
modules: _encodeEan13('0$value'),
|
||||
quietZoneModules: 11,
|
||||
);
|
||||
}
|
||||
if (value.length == 13 && hasValidGtinCheckDigit(value)) {
|
||||
return RetailBarcodeData(
|
||||
value: value,
|
||||
symbology: 'EAN-13',
|
||||
modules: _encodeEan13(value),
|
||||
quietZoneModules: 11,
|
||||
);
|
||||
}
|
||||
|
||||
return RetailBarcodeData(
|
||||
value: value,
|
||||
symbology: 'CODE 128',
|
||||
modules: _encodeCode128B(value),
|
||||
quietZoneModules: 10,
|
||||
);
|
||||
}
|
||||
|
||||
bool hasValidGtinCheckDigit(String value) {
|
||||
if (value.length < 2 || !RegExp(r'^\d+$').hasMatch(value)) return false;
|
||||
var sum = 0;
|
||||
var useThree = true;
|
||||
for (var i = value.length - 2; i >= 0; i--) {
|
||||
final digit = value.codeUnitAt(i) - 48;
|
||||
sum += digit * (useThree ? 3 : 1);
|
||||
useThree = !useThree;
|
||||
}
|
||||
final expected = (10 - (sum % 10)) % 10;
|
||||
return expected == value.codeUnitAt(value.length - 1) - 48;
|
||||
}
|
||||
|
||||
String _encodeEan13(String value) {
|
||||
final first = value.codeUnitAt(0) - 48;
|
||||
final parity = _ean13Parity[first];
|
||||
final out = StringBuffer('101');
|
||||
for (var i = 1; i <= 6; i++) {
|
||||
final digit = value.codeUnitAt(i) - 48;
|
||||
out.write(parity[i - 1] == 'L' ? _eanLeftOdd[digit] : _eanLeftEven[digit]);
|
||||
}
|
||||
out.write('01010');
|
||||
for (var i = 7; i <= 12; i++) {
|
||||
out.write(_eanRight[value.codeUnitAt(i) - 48]);
|
||||
}
|
||||
out.write('101');
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
String _encodeCode128B(String value) {
|
||||
const startB = 104;
|
||||
final codes = <int>[startB];
|
||||
var checksum = startB;
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
final code = value.codeUnitAt(i) - 32;
|
||||
codes.add(code);
|
||||
checksum += code * (i + 1);
|
||||
}
|
||||
codes
|
||||
..add(checksum % 103)
|
||||
..add(106);
|
||||
|
||||
final out = StringBuffer();
|
||||
for (final code in codes) {
|
||||
final widths = _code128Patterns[code];
|
||||
for (var i = 0; i < widths.length; i++) {
|
||||
final width = widths.codeUnitAt(i) - 48;
|
||||
out.write(List.filled(width, i.isEven ? '1' : '0').join());
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
Reference in New Issue
Block a user