feat: implement album art display functionality and update application version to dev50
Some checks failed
Build (3DS) / build (push) Failing after 1m59s
Some checks failed
Build (3DS) / build (push) Failing after 1m59s
This commit is contained in:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user