mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-08 06:00:08 +01:00
Logo: adds support for using media cover as logo source
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#include "media.h"
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media);
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover);
|
||||
|
||||
const FFMediaResult* ffDetectMedia(void)
|
||||
const FFMediaResult* ffDetectMedia(bool saveCover)
|
||||
{
|
||||
static FFMediaResult result;
|
||||
|
||||
@@ -17,7 +17,7 @@ const FFMediaResult* ffDetectMedia(void)
|
||||
ffStrbufInit(&result.url);
|
||||
ffStrbufInit(&result.status);
|
||||
ffStrbufInit(&result.cover);
|
||||
ffDetectMediaImpl(&result);
|
||||
ffDetectMediaImpl(&result, saveCover);
|
||||
|
||||
if(result.song.length == 0 && result.error.length == 0)
|
||||
ffStrbufAppendS(&result.error, "No media found");
|
||||
|
||||
@@ -16,4 +16,4 @@ typedef struct FFMediaResult
|
||||
FFstrbuf cover;
|
||||
} FFMediaResult;
|
||||
|
||||
const FFMediaResult* ffDetectMedia();
|
||||
const FFMediaResult* ffDetectMedia(bool saveCover);
|
||||
|
||||
@@ -13,7 +13,7 @@ extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queu
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
|
||||
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
{
|
||||
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
@@ -31,20 +31,24 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
|
||||
if (artworkData)
|
||||
|
||||
if (saveCover)
|
||||
{
|
||||
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
|
||||
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);
|
||||
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);
|
||||
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
|
||||
@@ -87,7 +91,7 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"), used))
|
||||
int ffPrintMediaByMediaRemote(void)
|
||||
int ffPrintMediaByMediaRemote(bool saveCover)
|
||||
{
|
||||
FFMediaResult media = {
|
||||
.status = ffStrbufCreate(),
|
||||
@@ -98,7 +102,7 @@ int ffPrintMediaByMediaRemote(void)
|
||||
.player = ffStrbufCreate(),
|
||||
.cover = ffStrbufCreate(),
|
||||
};
|
||||
if (getMediaByMediaRemote(&media) != NULL)
|
||||
if (getMediaByMediaRemote(&media, saveCover) != NULL)
|
||||
return 1;
|
||||
ffStrbufPutTo(&media.status, stdout);
|
||||
ffStrbufPutTo(&media.song, stdout);
|
||||
@@ -117,10 +121,10 @@ int ffPrintMediaByMediaRemote(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover)
|
||||
{
|
||||
// #1737
|
||||
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
|
||||
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote(%s)", instance.state.platform.exePath.chars, saveCover ? "True" : "False");
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
@@ -141,13 +145,13 @@ static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
|
||||
{
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
error = getMediaByAuthorizedProcess(media);
|
||||
error = getMediaByAuthorizedProcess(media, saveCover);
|
||||
else
|
||||
error = getMediaByMediaRemote(media);
|
||||
error = getMediaByMediaRemote(media, saveCover);
|
||||
if (error)
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
else if (media->player.length == 0 && media->playerId.length > 0)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/media/media.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/unused.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -271,8 +272,9 @@ static const char* getMedia(FFMediaResult* result)
|
||||
|
||||
#endif
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
|
||||
{
|
||||
FF_UNUSED(saveCover); // We don't save the cover to a file for Mpris implementation
|
||||
#ifdef FF_HAVE_DBUS
|
||||
const char* error = getMedia(media);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "media.h"
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
static const char* getMedia(FFMediaResult* media)
|
||||
static const char* getMedia(FFMediaResult* media, bool saveCover)
|
||||
{
|
||||
FF_LIBRARY_LOAD(libffwinrt, "dlopen libffwinrt" FF_LIBRARY_EXTENSION " failed", "libffwinrt" FF_LIBRARY_EXTENSION, 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia)
|
||||
@@ -11,7 +11,7 @@ static const char* getMedia(FFMediaResult* media)
|
||||
|
||||
FFWinrtMediaResult result = {};
|
||||
|
||||
const char* error = ffffWinrtDetectMedia(&result);
|
||||
const char* error = ffffWinrtDetectMedia(&result, saveCover);
|
||||
if (error)
|
||||
{
|
||||
ffStrbufSetStatic(&media->error, error);
|
||||
@@ -37,8 +37,8 @@ static const char* getMedia(FFMediaResult* media)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
|
||||
{
|
||||
const char* error = getMedia(media);
|
||||
const char* error = getMedia(media, saveCover);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
|
||||
@@ -10,14 +10,12 @@ extern "C"
|
||||
{
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover)
|
||||
{
|
||||
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
|
||||
// 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
|
||||
{
|
||||
@@ -66,33 +64,38 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
result->playerName[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
} catch (...) { }
|
||||
|
||||
if (auto thumbRef = mediaProps.Thumbnail())
|
||||
if (saveCover)
|
||||
{
|
||||
try
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt::Windows::Storage::Streams;
|
||||
if (auto thumbRef = mediaProps.Thumbnail())
|
||||
{
|
||||
if (auto stream = thumbRef.OpenReadAsync().get())
|
||||
try
|
||||
{
|
||||
if (stream.Size() > 0)
|
||||
if (auto stream = thumbRef.OpenReadAsync().get())
|
||||
{
|
||||
Buffer buffer(static_cast<uint32_t>(stream.Size()));
|
||||
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
|
||||
|
||||
wchar_t tempPath[MAX_PATH];
|
||||
if (GetTempPathW(MAX_PATH, tempPath) > 0)
|
||||
if (stream.Size() > 0)
|
||||
{
|
||||
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
|
||||
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
|
||||
FileIO::WriteBufferAsync(tempFile, buffer).get();
|
||||
Buffer buffer(static_cast<uint32_t>(stream.Size()));
|
||||
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
|
||||
|
||||
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\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 (...)
|
||||
{
|
||||
// Ignore thumbnail errors
|
||||
catch (...)
|
||||
{
|
||||
// Ignore thumbnail errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ typedef struct FFWinrtMediaResult
|
||||
} FFWinrtMediaResult;
|
||||
|
||||
__attribute__((__dllexport__))
|
||||
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result);
|
||||
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover);
|
||||
|
||||
Reference in New Issue
Block a user