feat: implement album art display functionality and update application version to dev50
Some checks failed
Build (3DS) / build (push) Failing after 1m59s

This commit is contained in:
2025-12-06 23:31:45 -06:00
parent 8be23ca4fc
commit d09cf0739e
6 changed files with 321 additions and 48 deletions

View File

@@ -194,56 +194,135 @@ static int extractId3v2Metadata(FILE* fp, struct metadata_t* metadata)
continue;
}
if(fread(frameData, 1, frameSize, fp) == frameSize)
if(fread(frameData, 1, frameSize, fp) == frameSize)
{
frameData[frameSize] = 0;
/* Text encoding byte:
* 0x00 = ISO-8859-1
* 0x01 = UTF-16 with BOM
* 0x02 = UTF-16BE without BOM
* 0x03 = UTF-8
*/
uint8_t encoding = frameData[0];
char* text = frameData + 1;
int textLen = frameSize - 1;
/* Skip UTF-16 BOM if present */
if(encoding == 0x01 && textLen >= 2)
{
frameData[frameSize] = 0;
/* Skip text encoding byte */
char* text = frameData + 1;
int textLen = frameSize - 1;
/* Copy to appropriate field */
char* dest = NULL;
size_t maxLen = 0;
if(strncmp(frameId, "TIT2", 4) == 0)
if((uint8_t)text[0] == 0xFF && (uint8_t)text[1] == 0xFE)
{
dest = metadata->title;
maxLen = METADATA_TITLE_MAX - 1;
text += 2;
textLen -= 2;
}
else if(strncmp(frameId, "TPE1", 4) == 0)
else if((uint8_t)text[0] == 0xFE && (uint8_t)text[1] == 0xFF)
{
dest = metadata->artist;
maxLen = METADATA_ARTIST_MAX - 1;
}
else if(strncmp(frameId, "TALB", 4) == 0)
{
dest = metadata->album;
maxLen = METADATA_ALBUM_MAX - 1;
}
if(dest)
{
strncpy(dest, text, maxLen);
dest[maxLen] = 0;
trimWhitespace(dest);
text += 2;
textLen -= 2;
}
}
free(frameData);
/* Copy to appropriate field */
char* dest = NULL;
size_t maxLen = 0;
if(strncmp(frameId, "TIT2", 4) == 0)
{
dest = metadata->title;
maxLen = METADATA_TITLE_MAX - 1;
}
else if(strncmp(frameId, "TPE1", 4) == 0)
{
dest = metadata->artist;
maxLen = METADATA_ARTIST_MAX - 1;
}
else if(strncmp(frameId, "TALB", 4) == 0)
{
dest = metadata->album;
maxLen = METADATA_ALBUM_MAX - 1;
}
if(dest)
{
/* Handle different encodings */
if(encoding == 0x01 || encoding == 0x02) /* UTF-16 */
{
/* Convert UTF-16 to ASCII (simplified - just take every other byte) */
int outPos = 0;
for(int i = 0; i < textLen && outPos < (int)maxLen; i += 2)
{
if(text[i] >= 0x20 && text[i] < 0x7F)
dest[outPos++] = text[i];
else if(text[i] == 0 && text[i+1] == 0)
break;
}
dest[outPos] = 0;
}
else /* ISO-8859-1 or UTF-8 */
{
/* Copy as-is, filtering out non-ASCII characters */
int outPos = 0;
for(int i = 0; i < textLen && outPos < (int)maxLen; i++)
{
if((uint8_t)text[i] >= 0x20 && (uint8_t)text[i] < 0x7F)
dest[outPos++] = text[i];
else if(text[i] == 0)
break;
}
dest[outPos] = 0;
}
trimWhitespace(dest);
}
} free(frameData);
}
else if(strncmp(frameId, "APIC", 4) == 0) /* Attached Picture */
{
/* Basic album art detection - just store size info for now */
/* Extract album art data */
if(frameSize > 10 && !metadata->hasAlbumArt)
{
metadata->hasAlbumArt = true;
metadata->albumArtSize = frameSize;
/* Estimate dimensions - actual implementation would decode image */
metadata->albumArtWidth = 300; /* Common album art size */
metadata->albumArtHeight = 300;
uint8_t* frameData = malloc(frameSize);
if(frameData && fread(frameData, 1, frameSize, fp) == frameSize)
{
/* ID3v2 APIC frame format:
* - Text encoding (1 byte)
* - MIME type (null-terminated string)
* - Picture type (1 byte)
* - Description (null-terminated string)
* - Picture data
*/
uint8_t* ptr = frameData;
ptr++; /* Skip text encoding */
/* Skip MIME type */
while(*ptr != 0 && (ptr - frameData) < (int)frameSize) ptr++;
ptr++; /* Skip null terminator */
ptr++; /* Skip picture type */
/* Skip description */
while(*ptr != 0 && (ptr - frameData) < (int)frameSize) ptr++;
ptr++; /* Skip null terminator */
/* Remaining data is the image */
size_t imageSize = frameSize - (ptr - frameData);
if(imageSize > 0)
{
metadata->albumArt = malloc(imageSize);
if(metadata->albumArt)
{
memcpy(metadata->albumArt, ptr, imageSize);
metadata->albumArtSize = imageSize;
metadata->hasAlbumArt = true;
}
}
}
if(frameData) free(frameData);
}
else
{
fseek(fp, frameSize, SEEK_CUR);
}
fseek(fp, frameSize, SEEK_CUR);
}
else
{
@@ -415,7 +494,72 @@ static int extractFlacMetadata(FILE* fp, struct metadata_t* metadata)
blockType = blockHeader[0] & 0x7F;
blockSize = (blockHeader[1] << 16) | (blockHeader[2] << 8) | blockHeader[3];
if(blockType == 4) /* VORBIS_COMMENT */
if(blockType == 6) /* PICTURE */
{
/* Extract album art from FLAC picture block */
if(!metadata->hasAlbumArt && blockSize > 32)
{
uint8_t* pictureData = malloc(blockSize);
if(pictureData && fread(pictureData, 1, blockSize, fp) == blockSize)
{
/* FLAC picture block format:
* - Picture type (4 bytes BE)
* - MIME type length (4 bytes BE)
* - MIME type string
* - Description length (4 bytes BE)
* - Description string
* - Width (4 bytes BE)
* - Height (4 bytes BE)
* - Depth (4 bytes BE)
* - Colors (4 bytes BE)
* - Picture data length (4 bytes BE)
* - Picture data
*/
uint32_t offset = 4; /* Skip picture type */
/* Skip MIME type */
uint32_t mimeLen = (pictureData[offset] << 24) | (pictureData[offset+1] << 16) |
(pictureData[offset+2] << 8) | pictureData[offset+3];
offset += 4 + mimeLen;
/* Skip description */
if(offset + 4 <= blockSize)
{
uint32_t descLen = (pictureData[offset] << 24) | (pictureData[offset+1] << 16) |
(pictureData[offset+2] << 8) | pictureData[offset+3];
offset += 4 + descLen;
}
/* Skip width, height, depth, colors (16 bytes) */
offset += 16;
/* Get picture data length */
if(offset + 4 <= blockSize)
{
uint32_t picLen = (pictureData[offset] << 24) | (pictureData[offset+1] << 16) |
(pictureData[offset+2] << 8) | pictureData[offset+3];
offset += 4;
if(offset + picLen <= blockSize && picLen > 0)
{
metadata->albumArt = malloc(picLen);
if(metadata->albumArt)
{
memcpy(metadata->albumArt, pictureData + offset, picLen);
metadata->albumArtSize = picLen;
metadata->hasAlbumArt = true;
}
}
}
}
if(pictureData) free(pictureData);
}
else
{
fseek(fp, blockSize, SEEK_CUR);
}
}
else if(blockType == 4) /* VORBIS_COMMENT */
{
/* FLAC uses Vorbis comments for metadata */
/* This is a simplified implementation */