Media: save media cover to temp file

This commit is contained in:
李通洲
2025-10-21 13:56:46 +08:00
parent faddef7a3b
commit 5d73cc1232
5 changed files with 43 additions and 37 deletions
+18 -7
View File
@@ -5,6 +5,7 @@
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <CoreServices/CoreServices.h>
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
@@ -30,7 +31,21 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
ffCfDictGetDataAsString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"), &result->cover);
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
if (artworkData)
{
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
FF_CFTYPE_AUTO_RELEASE CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mime, NULL);
FF_CFTYPE_AUTO_RELEASE CFStringRef ext = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
#pragma clang diagnostic pop
NSString *tmpDir = NSTemporaryDirectory();
NSString *uuid = [[NSUUID UUID] UUIDString];
NSString *path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString *) ext : @"img"]];
if ([artworkData writeToFile:path atomically:NO])
ffStrbufSetS(&result->cover, path.UTF8String);
}
}
else
error = "MRMediaRemoteGetNowPlayingInfo() failed";
@@ -91,7 +106,7 @@ int ffPrintMediaByMediaRemote(void)
ffStrbufPutTo(&media.album, stdout);
ffStrbufPutTo(&media.playerId, stdout);
ffStrbufPutTo(&media.player, stdout);
ffStrbufWriteTo(&media.cover, stdout); // Raw data
ffStrbufWriteTo(&media.cover, stdout);
ffStrbufDestroy(&media.status);
ffStrbufDestroy(&media.song);
ffStrbufDestroy(&media.artist);
@@ -118,15 +133,11 @@ static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
if (buffer.length == 0) return "No media found";
// status\ntitle\nartist\nalbum\nbundleName\nappName
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player, &result->cover };
char* line = NULL;
size_t len = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
ffStrbufSetS(varList[i], line);
ffStrbufGetlineRestore(&line, &len, &buffer);
line++; // Skip the newline before the cover data
if (line < buffer.chars + buffer.length)
ffStrbufSetNS(&result->cover, buffer.length - (uint32_t) (line - buffer.chars), line);
return NULL;
}
+4 -7
View File
@@ -77,8 +77,8 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
ffDBusGetString(data, &dictIterator, &path);
if (ffStrbufStartsWithS(&path, "file:///"))
{
uint32_t j = 0;
for (uint32_t i = (uint32_t) strlen("file:///") - 1; i < path.length; ++i, ++j)
ffStrbufEnsureFree(&result->cover, path.length - (uint32_t) strlen("file://"));
for (uint32_t i = (uint32_t) strlen("file://"); i < path.length; ++i)
{
if (path.chars[i] == '%')
{
@@ -86,17 +86,14 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
break;
char str[] = { path.chars[i + 1], path.chars[i + 2], 0 };
const char decodedChar = (char) strtoul(str, NULL, 16);
path.chars[j] = decodedChar;
i += 2;
ffStrbufAppendC(&result->cover, decodedChar);
}
else
{
path.chars[j] = path.chars[i];
ffStrbufAppendC(&result->cover, path.chars[i]);
}
}
path.chars[j] = '\0';
path.length = j;
ffReadFileBuffer(path.chars, &result->cover);
}
}
}
+1 -5
View File
@@ -32,12 +32,8 @@ static const char* getMedia(FFMediaResult* media)
ffStrbufSetWS(&media->song, result.song);
ffStrbufSetWS(&media->artist, result.artist);
ffStrbufSetWS(&media->album, result.album);
ffStrbufSetWS(&media->cover, result.cover);
ffStrbufSetStatic(&media->status, result.status);
ffStrbufDestroy(&media->cover);
media->cover.chars = (char*) result.coverImageData;
media->cover.length = result.coverImageSize;
media->cover.allocated = result.coverImageSize + 1;
return NULL;
}
+19 -14
View File
@@ -2,9 +2,9 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Control.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Storage.h>
#include <wchar.h>
#include <stdlib.h>
#include <windows.h>
extern "C"
{
@@ -16,6 +16,7 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
// Make it a separate dll in order not to break Windows 7 support
using namespace winrt::Windows::Media::Control;
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::Storage;
using namespace winrt::Windows::Storage::Streams;
try
@@ -69,20 +70,24 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
{
try
{
auto stream = thumbRef.OpenReadAsync().get();
uint64_t size = stream.Size();
if (size > 0)
if (auto stream = thumbRef.OpenReadAsync().get())
{
auto contentType = stream.ContentType();
auto ibuffer = Buffer(static_cast<uint32_t>(size));
auto readBuffer = stream.ReadAsync(ibuffer, static_cast<uint32_t>(size), InputStreamOptions::None).get();
uint32_t length = readBuffer.Length();
auto reader = DataReader::FromBuffer(readBuffer);
if (stream.Size() > 0)
{
Buffer buffer(static_cast<uint32_t>(stream.Size()));
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
result->coverImageSize = length;
result->coverImageData = (uint8_t*) ::malloc(length + 1);
reader.ReadBytes(winrt::array_view<uint8_t>(result->coverImageData, result->coverImageSize));
result->coverImageData[length] = 0;
wchar_t tempPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, tempPath) > 0)
{
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
FileIO::WriteBufferAsync(tempFile, buffer).get();
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
}
}
}
}
catch (...)
+1 -4
View File
@@ -9,11 +9,8 @@ typedef struct FFWinrtMediaResult
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t cover[FF_MEDIA_WIN_RESULT_BUFLEN];
const char* status;
// Caller is responsible for freeing it using free()
uint8_t* coverImageData;
uint32_t coverImageSize;
} FFWinrtMediaResult;
__attribute__((__dllexport__))