diff --git a/src/detection/media/media.c b/src/detection/media/media.c index ddb2631a4..7ff7e16bd 100644 --- a/src/detection/media/media.c +++ b/src/detection/media/media.c @@ -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"); diff --git a/src/detection/media/media.h b/src/detection/media/media.h index 2527f6e28..2bee25c41 100644 --- a/src/detection/media/media.h +++ b/src/detection/media/media.h @@ -16,4 +16,4 @@ typedef struct FFMediaResult FFstrbuf cover; } FFMediaResult; -const FFMediaResult* ffDetectMedia(); +const FFMediaResult* ffDetectMedia(bool saveCover); diff --git a/src/detection/media/media_apple.m b/src/detection/media/media_apple.m index b3dbc8822..c3cb41bd9 100644 --- a/src/detection/media/media_apple.m +++ b/src/detection/media/media_apple.m @@ -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) diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index 5daa93605..7bd2d2ff8 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -2,6 +2,7 @@ #include "fastfetch.h" #include "detection/media/media.h" #include "util/stringUtils.h" +#include "util/unused.h" #include @@ -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); diff --git a/src/detection/media/media_windows.c b/src/detection/media/media_windows.c index 37c083a42..51810e423 100644 --- a/src/detection/media/media_windows.c +++ b/src/detection/media/media_windows.c @@ -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); } diff --git a/src/detection/media/media_windows.dll.cpp b/src/detection/media/media_windows.dll.cpp index 0ea2987dd..b8a23b9e8 100644 --- a/src/detection/media/media_windows.dll.cpp +++ b/src/detection/media/media_windows.dll.cpp @@ -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(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(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 + } } } diff --git a/src/detection/media/media_windows.dll.h b/src/detection/media/media_windows.dll.h index 005d3cf62..9d4e37755 100644 --- a/src/detection/media/media_windows.dll.h +++ b/src/detection/media/media_windows.dll.h @@ -14,4 +14,4 @@ typedef struct FFWinrtMediaResult } FFWinrtMediaResult; __attribute__((__dllexport__)) -const char* ffWinrtDetectMedia(FFWinrtMediaResult* result); +const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover); diff --git a/src/logo/logo.c b/src/logo/logo.c index a0d64b72f..bb1398e5e 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -2,6 +2,7 @@ #include "common/io/io.h" #include "common/printing.h" #include "common/processing.h" +#include "detection/media/media.h" #include "detection/os/os.h" #include "detection/terminalshell/terminalshell.h" #include "util/textModifier.h" @@ -483,6 +484,15 @@ static bool updateLogoPath(void) if (ffStrbufEqualS(&options->source, "-")) // stdin return true; + if (ffStrbufIgnCaseEqualS(&options->source, "mediacover")) + { + const FFMediaResult* media = ffDetectMedia(true); + if (media->cover.length == 0) + return false; + ffStrbufSet(&options->source, &media->cover); + return true; + } + FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreate(); if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE)) { diff --git a/src/modules/media/media.c b/src/modules/media/media.c index f82b4b856..f14c53589 100644 --- a/src/modules/media/media.c +++ b/src/modules/media/media.c @@ -43,7 +43,7 @@ static bool artistInSongTitle(const FFstrbuf* song, const FFstrbuf* artist) bool ffPrintMedia(FFMediaOptions* options) { - const FFMediaResult* media = ffDetectMedia(); + const FFMediaResult* media = ffDetectMedia(false); if(media->error.length > 0) { @@ -128,7 +128,7 @@ void ffGenerateMediaJsonConfig(FFMediaOptions* options, yyjson_mut_doc* doc, yyj bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - const FFMediaResult* media = ffDetectMedia(); + const FFMediaResult* media = ffDetectMedia(false); if(media->error.length > 0) { @@ -143,6 +143,10 @@ bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_m yyjson_mut_obj_add_strbuf(doc, song, "artist", &media->artist); yyjson_mut_obj_add_strbuf(doc, song, "album", &media->album); yyjson_mut_obj_add_strbuf(doc, song, "status", &media->status); + if (media->cover.length > 0) + yyjson_mut_obj_add_strbuf(doc, song, "cover", &media->status); + else + yyjson_mut_obj_add_null(doc, song, "cover"); yyjson_mut_val* player = yyjson_mut_obj_add_obj(doc, obj, "player"); yyjson_mut_obj_add_strbuf(doc, player, "name", &media->player); diff --git a/src/modules/player/player.c b/src/modules/player/player.c index 69002cb48..62592dced 100644 --- a/src/modules/player/player.c +++ b/src/modules/player/player.c @@ -10,7 +10,7 @@ bool ffPrintPlayer(FFPlayerOptions* options) { - const FFMediaResult* media = ffDetectMedia(); + const FFMediaResult* media = ffDetectMedia(false); if(media->error.length > 0) {