Skip to content

Commit 338b552

Browse files
committed
Logo: adds support for using media cover as logo source
1 parent 5d73cc1 commit 338b552

File tree

10 files changed

+75
-52
lines changed

10 files changed

+75
-52
lines changed

src/detection/media/media.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "media.h"
22

3-
void ffDetectMediaImpl(FFMediaResult* media);
3+
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover);
44

5-
const FFMediaResult* ffDetectMedia(void)
5+
const FFMediaResult* ffDetectMedia(bool saveCover)
66
{
77
static FFMediaResult result;
88

@@ -17,7 +17,7 @@ const FFMediaResult* ffDetectMedia(void)
1717
ffStrbufInit(&result.url);
1818
ffStrbufInit(&result.status);
1919
ffStrbufInit(&result.cover);
20-
ffDetectMediaImpl(&result);
20+
ffDetectMediaImpl(&result, saveCover);
2121

2222
if(result.song.length == 0 && result.error.length == 0)
2323
ffStrbufAppendS(&result.error, "No media found");

src/detection/media/media.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ typedef struct FFMediaResult
1616
FFstrbuf cover;
1717
} FFMediaResult;
1818

19-
const FFMediaResult* ffDetectMedia();
19+
const FFMediaResult* ffDetectMedia(bool saveCover);

src/detection/media/media_apple.m

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
1414
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
1515

16-
static const char* getMediaByMediaRemote(FFMediaResult* result)
16+
static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
1717
{
1818
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
1919
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
@@ -31,20 +31,24 @@
3131
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
3232
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
3333
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
34-
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
35-
if (artworkData)
34+
35+
if (saveCover)
3636
{
37-
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
37+
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
38+
if (artworkData)
39+
{
40+
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
3841
#pragma clang diagnostic push
3942
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
40-
FF_CFTYPE_AUTO_RELEASE CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mime, NULL);
41-
FF_CFTYPE_AUTO_RELEASE CFStringRef ext = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
43+
FF_CFTYPE_AUTO_RELEASE CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mime, NULL);
44+
FF_CFTYPE_AUTO_RELEASE CFStringRef ext = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
4245
#pragma clang diagnostic pop
43-
NSString *tmpDir = NSTemporaryDirectory();
44-
NSString *uuid = [[NSUUID UUID] UUIDString];
45-
NSString *path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString *) ext : @"img"]];
46-
if ([artworkData writeToFile:path atomically:NO])
47-
ffStrbufSetS(&result->cover, path.UTF8String);
46+
NSString *tmpDir = NSTemporaryDirectory();
47+
NSString *uuid = [[NSUUID UUID] UUIDString];
48+
NSString *path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString *) ext : @"img"]];
49+
if ([artworkData writeToFile:path atomically:NO])
50+
ffStrbufSetS(&result->cover, path.UTF8String);
51+
}
4852
}
4953
}
5054
else
@@ -87,7 +91,7 @@
8791
}
8892

8993
__attribute__((visibility("default"), used))
90-
int ffPrintMediaByMediaRemote(void)
94+
int ffPrintMediaByMediaRemote(bool saveCover)
9195
{
9296
FFMediaResult media = {
9397
.status = ffStrbufCreate(),
@@ -98,7 +102,7 @@ int ffPrintMediaByMediaRemote(void)
98102
.player = ffStrbufCreate(),
99103
.cover = ffStrbufCreate(),
100104
};
101-
if (getMediaByMediaRemote(&media) != NULL)
105+
if (getMediaByMediaRemote(&media, saveCover) != NULL)
102106
return 1;
103107
ffStrbufPutTo(&media.status, stdout);
104108
ffStrbufPutTo(&media.song, stdout);
@@ -117,10 +121,10 @@ int ffPrintMediaByMediaRemote(void)
117121
return 0;
118122
}
119123

120-
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
124+
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover)
121125
{
122126
// #1737
123-
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
127+
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote(%s)", instance.state.platform.exePath.chars, saveCover ? "True" : "False");
124128
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
125129

126130
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
@@ -141,13 +145,13 @@ int ffPrintMediaByMediaRemote(void)
141145
return NULL;
142146
}
143147

144-
void ffDetectMediaImpl(FFMediaResult* media)
148+
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
145149
{
146150
const char* error;
147151
if (@available(macOS 15.4, *))
148-
error = getMediaByAuthorizedProcess(media);
152+
error = getMediaByAuthorizedProcess(media, saveCover);
149153
else
150-
error = getMediaByMediaRemote(media);
154+
error = getMediaByMediaRemote(media, saveCover);
151155
if (error)
152156
ffStrbufAppendS(&media->error, error);
153157
else if (media->player.length == 0 && media->playerId.length > 0)

src/detection/media/media_linux.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "fastfetch.h"
33
#include "detection/media/media.h"
44
#include "util/stringUtils.h"
5+
#include "util/unused.h"
56

67
#include <string.h>
78

@@ -271,8 +272,9 @@ static const char* getMedia(FFMediaResult* result)
271272

272273
#endif
273274

274-
void ffDetectMediaImpl(FFMediaResult* media)
275+
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
275276
{
277+
FF_UNUSED(saveCover); // We don't save the cover to a file for Mpris implementation
276278
#ifdef FF_HAVE_DBUS
277279
const char* error = getMedia(media);
278280
ffStrbufAppendS(&media->error, error);

src/detection/media/media_windows.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
#include "media.h"
44
#include "media_windows.dll.h"
55

6-
static const char* getMedia(FFMediaResult* media)
6+
static const char* getMedia(FFMediaResult* media, bool saveCover)
77
{
88
FF_LIBRARY_LOAD(libffwinrt, "dlopen libffwinrt" FF_LIBRARY_EXTENSION " failed", "libffwinrt" FF_LIBRARY_EXTENSION, 0)
99
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia)
1010
libffwinrt = NULL; // Don't close libffwinrt or it may crash
1111

1212
FFWinrtMediaResult result = {};
1313

14-
const char* error = ffffWinrtDetectMedia(&result);
14+
const char* error = ffffWinrtDetectMedia(&result, saveCover);
1515
if (error)
1616
{
1717
ffStrbufSetStatic(&media->error, error);
@@ -37,8 +37,8 @@ static const char* getMedia(FFMediaResult* media)
3737
return NULL;
3838
}
3939

40-
void ffDetectMediaImpl(FFMediaResult* media)
40+
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
4141
{
42-
const char* error = getMedia(media);
42+
const char* error = getMedia(media, saveCover);
4343
ffStrbufAppendS(&media->error, error);
4444
}

src/detection/media/media_windows.dll.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ extern "C"
1010
{
1111
#include "media_windows.dll.h"
1212

13-
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
13+
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover)
1414
{
1515
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
1616
// Make it a separate dll in order not to break Windows 7 support
1717
using namespace winrt::Windows::Media::Control;
1818
using namespace winrt::Windows::ApplicationModel;
19-
using namespace winrt::Windows::Storage;
20-
using namespace winrt::Windows::Storage::Streams;
2119

2220
try
2321
{
@@ -66,33 +64,38 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
6664
result->playerName[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
6765
} catch (...) { }
6866

69-
if (auto thumbRef = mediaProps.Thumbnail())
67+
if (saveCover)
7068
{
71-
try
69+
using namespace winrt::Windows::Storage;
70+
using namespace winrt::Windows::Storage::Streams;
71+
if (auto thumbRef = mediaProps.Thumbnail())
7272
{
73-
if (auto stream = thumbRef.OpenReadAsync().get())
73+
try
7474
{
75-
if (stream.Size() > 0)
75+
if (auto stream = thumbRef.OpenReadAsync().get())
7676
{
77-
Buffer buffer(static_cast<uint32_t>(stream.Size()));
78-
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
79-
80-
wchar_t tempPath[MAX_PATH];
81-
if (GetTempPathW(MAX_PATH, tempPath) > 0)
77+
if (stream.Size() > 0)
8278
{
83-
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
84-
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
85-
FileIO::WriteBufferAsync(tempFile, buffer).get();
79+
Buffer buffer(static_cast<uint32_t>(stream.Size()));
80+
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
81+
82+
wchar_t tempPath[MAX_PATH];
83+
if (GetTempPathW(MAX_PATH, tempPath) > 0)
84+
{
85+
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
86+
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
87+
FileIO::WriteBufferAsync(tempFile, buffer).get();
8688

87-
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
88-
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
89+
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
90+
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
91+
}
8992
}
9093
}
9194
}
92-
}
93-
catch (...)
94-
{
95-
// Ignore thumbnail errors
95+
catch (...)
96+
{
97+
// Ignore thumbnail errors
98+
}
9699
}
97100
}
98101

src/detection/media/media_windows.dll.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ typedef struct FFWinrtMediaResult
1414
} FFWinrtMediaResult;
1515

1616
__attribute__((__dllexport__))
17-
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result);
17+
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover);

src/logo/logo.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "common/io/io.h"
33
#include "common/printing.h"
44
#include "common/processing.h"
5+
#include "detection/media/media.h"
56
#include "detection/os/os.h"
67
#include "detection/terminalshell/terminalshell.h"
78
#include "util/textModifier.h"
@@ -483,6 +484,15 @@ static bool updateLogoPath(void)
483484
if (ffStrbufEqualS(&options->source, "-")) // stdin
484485
return true;
485486

487+
if (ffStrbufIgnCaseEqualS(&options->source, "mediacover"))
488+
{
489+
const FFMediaResult* media = ffDetectMedia(true);
490+
if (media->cover.length == 0)
491+
return false;
492+
ffStrbufSet(&options->source, &media->cover);
493+
return true;
494+
}
495+
486496
FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreate();
487497
if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE))
488498
{

src/modules/media/media.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static bool artistInSongTitle(const FFstrbuf* song, const FFstrbuf* artist)
4343

4444
bool ffPrintMedia(FFMediaOptions* options)
4545
{
46-
const FFMediaResult* media = ffDetectMedia();
46+
const FFMediaResult* media = ffDetectMedia(false);
4747

4848
if(media->error.length > 0)
4949
{
@@ -128,7 +128,7 @@ void ffGenerateMediaJsonConfig(FFMediaOptions* options, yyjson_mut_doc* doc, yyj
128128

129129
bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
130130
{
131-
const FFMediaResult* media = ffDetectMedia();
131+
const FFMediaResult* media = ffDetectMedia(false);
132132

133133
if(media->error.length > 0)
134134
{
@@ -143,6 +143,10 @@ bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_m
143143
yyjson_mut_obj_add_strbuf(doc, song, "artist", &media->artist);
144144
yyjson_mut_obj_add_strbuf(doc, song, "album", &media->album);
145145
yyjson_mut_obj_add_strbuf(doc, song, "status", &media->status);
146+
if (media->cover.length > 0)
147+
yyjson_mut_obj_add_strbuf(doc, song, "cover", &media->status);
148+
else
149+
yyjson_mut_obj_add_null(doc, song, "cover");
146150

147151
yyjson_mut_val* player = yyjson_mut_obj_add_obj(doc, obj, "player");
148152
yyjson_mut_obj_add_strbuf(doc, player, "name", &media->player);

src/modules/player/player.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
bool ffPrintPlayer(FFPlayerOptions* options)
1212
{
13-
const FFMediaResult* media = ffDetectMedia();
13+
const FFMediaResult* media = ffDetectMedia(false);
1414

1515
if(media->error.length > 0)
1616
{

0 commit comments

Comments
 (0)