mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-29 16:26:39 +01:00
Media (Windows): major code refactor
moves detection code into fastfetch binary Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
+23
-24
@@ -160,7 +160,11 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointe
|
||||
|
||||
if(WIN32 OR Haiku)
|
||||
enable_language(CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
endif()
|
||||
|
||||
@@ -1065,7 +1069,7 @@ elseif(WIN32)
|
||||
src/detection/locale/locale_windows.c
|
||||
src/detection/localip/localip_windows.c
|
||||
src/detection/gamepad/gamepad_windows.c
|
||||
src/detection/media/media_windows.c
|
||||
src/detection/media/media_windows.cpp
|
||||
src/detection/memory/memory_windows.c
|
||||
src/detection/mouse/mouse_windows.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
@@ -1332,6 +1336,14 @@ endif()
|
||||
if(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_intel.c)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_amd.c)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
message(STATUS "WinRT headers are available, media detection will use WinRT APIs")
|
||||
else()
|
||||
message(STATUS "WinRT headers are NOT available, media detection will be disabled")
|
||||
endif()
|
||||
endif()
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(wcwidth HAVE_WCWIDTH)
|
||||
@@ -1434,7 +1446,7 @@ if(LINUX)
|
||||
elseif(ANDROID)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE _FILE_OFFSET_BITS=64 "$<$<CONFIG:DEBUG>:__BIONIC_FORTIFY>" "$<$<CONFIG:DEBUG>:__BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED>")
|
||||
elseif(WIN32)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 NOMINMAX UNICODE) # "$<$<CONFIG:Release>:_FORTIFY_SOURCE=3>"
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 NOMINMAX UNICODE) # "$<$<CONFIG:Release>:_FORTIFY_SOURCE=3>"
|
||||
elseif(APPLE)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE __STDC_WANT_LIB_EXT1__ _FILE_OFFSET_BITS=64 _DARWIN_C_SOURCE)
|
||||
elseif(OpenBSD)
|
||||
@@ -1745,6 +1757,12 @@ elseif(WIN32)
|
||||
PRIVATE "mincore"
|
||||
)
|
||||
endif()
|
||||
if(HAVE_WINRT)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE
|
||||
"RuntimeObject"
|
||||
)
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
@@ -1831,20 +1849,6 @@ target_link_libraries(libfastfetch
|
||||
target_compile_options(libfastfetch PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
add_library(ffwinrt MODULE src/detection/media/media_windows.dll.cpp)
|
||||
target_link_libraries(ffwinrt PRIVATE "RuntimeObject")
|
||||
target_compile_definitions(ffwinrt PRIVATE WIN32_LEAN_AND_MEAN=1 WINRT_LEAN_AND_MEAN=1)
|
||||
target_link_options(ffwinrt
|
||||
PRIVATE "-static" # stdc++, winpthread, gcc_s, etc.
|
||||
)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
if(FreeBSD)
|
||||
set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include")
|
||||
endif()
|
||||
@@ -1891,6 +1895,8 @@ if(NOT WIN32)
|
||||
message(WARNING "pthread_timedjoin_np was not found; networking timeout will not work")
|
||||
endif()
|
||||
endif()
|
||||
elseif(HAVE_WINRT)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WINRT=1)
|
||||
endif()
|
||||
|
||||
set(PACKAGES_DISABLE_LIST "")
|
||||
@@ -2037,13 +2043,6 @@ if (TARGET flashfetch)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (TARGET ffwinrt)
|
||||
install(
|
||||
TARGETS ffwinrt
|
||||
DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES "${CMAKE_SOURCE_DIR}/completions/${CMAKE_PROJECT_NAME}.bash"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions"
|
||||
|
||||
@@ -260,6 +260,9 @@ void ffListFeatures(void) {
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_HAVE_WINRT
|
||||
"WinRT headers\n"
|
||||
#endif
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "common/attributes.h"
|
||||
#include <unknwn.h>
|
||||
|
||||
const char* ffInitCom(void);
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "common/library.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "media.h"
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
static const char* getMedia(FFMediaResult* media, bool saveCover) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(libffwinrt, "libffwinrt" FF_LIBRARY_EXTENSION, 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia)
|
||||
libffwinrt = NULL; // Don't close libffwinrt or it may crash
|
||||
|
||||
FFWinrtMediaResult result = {};
|
||||
|
||||
const char* error = ffffWinrtDetectMedia(&result, saveCover);
|
||||
if (error) {
|
||||
ffStrbufSetStatic(&media->error, error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ffStrbufSetWS(&media->playerId, result.playerId);
|
||||
if (result.playerName[0]) {
|
||||
ffStrbufSetWS(&media->player, result.playerName);
|
||||
} else {
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe")) {
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (media->cover.length > 0) {
|
||||
media->removeCoverAfterUse = true;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
|
||||
const char* error = getMedia(media, saveCover);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
extern "C" {
|
||||
#include "media.h"
|
||||
#include "common/time.h"
|
||||
#include "common/windows/unicode.h"
|
||||
}
|
||||
|
||||
#if FF_HAVE_WINRT
|
||||
#include <roapi.h>
|
||||
#include <robuffer.h>
|
||||
#include <winstring.h>
|
||||
#include <asyncinfo.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
|
||||
#include "common/windows/com.hpp"
|
||||
|
||||
using winrt::impl::abi_t;
|
||||
using winrt::Windows::Foundation::IAsyncOperation;
|
||||
using winrt::Windows::Foundation::IAsyncOperationWithProgress;
|
||||
|
||||
static inline void deleteHstring(HSTRING* pstr) {
|
||||
if (*pstr) {
|
||||
WindowsDeleteString(*pstr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value) {
|
||||
uint32_t length = 0;
|
||||
const wchar_t* raw = WindowsGetStringRawBuffer(value, &length);
|
||||
ffStrbufSetNWS(destination, length, raw);
|
||||
}
|
||||
|
||||
template <typename Interface>
|
||||
static inline HRESULT ffGetActivationFactory(const wchar_t* className, REFIID iid, Interface** factory) {
|
||||
HSTRING_HEADER header;
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING runtimeClass = NULL;
|
||||
HRESULT hr = WindowsCreateStringReference(className, (UINT32)::wcslen(className), &header, &runtimeClass);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return RoGetActivationFactory(runtimeClass, iid, reinterpret_cast<void**>(factory));
|
||||
}
|
||||
|
||||
template <typename TargetProjection, typename SourceAbi, typename TargetAbi>
|
||||
static inline HRESULT ffQueryInterface(SourceAbi* source, TargetAbi** target) {
|
||||
*target = NULL;
|
||||
return reinterpret_cast<IUnknown*>(source)->QueryInterface(winrt::guid_of<TargetProjection>(), reinterpret_cast<void**>(target));
|
||||
}
|
||||
|
||||
template <typename TOperationAbi, typename TResultAbi>
|
||||
static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) {
|
||||
*result = NULL;
|
||||
|
||||
IAsyncInfo* FF_AUTO_RELEASE_COM_OBJECT asyncInfo = NULL;
|
||||
HRESULT hr = ffQueryInterface<IAsyncInfo>(operation, &asyncInfo);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
AsyncStatus status = AsyncStatus::Started;
|
||||
|
||||
for (;;) {
|
||||
hr = asyncInfo->get_Status(&status);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (status == AsyncStatus::Started) {
|
||||
ffTimeSleep(0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != AsyncStatus::Completed) {
|
||||
HRESULT errorCode = E_FAIL;
|
||||
asyncInfo->get_ErrorCode(&errorCode);
|
||||
return FAILED(errorCode) ? errorCode : E_FAIL;
|
||||
}
|
||||
|
||||
return operation->GetResults((void**) result);
|
||||
}
|
||||
|
||||
static HRESULT ffSaveThumbnailToTempPath(
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* thumbnail,
|
||||
FFstrbuf* destination) {
|
||||
abi_t<IAsyncOperation<winrt::Windows::Storage::Streams::IRandomAccessStreamWithContentType>>* FF_AUTO_RELEASE_COM_OBJECT openOperation = NULL;
|
||||
HRESULT hr = thumbnail->OpenReadAsync(reinterpret_cast<void**>(&openOperation));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamWithContentType>* FF_AUTO_RELEASE_COM_OBJECT contentStream = NULL;
|
||||
hr = ffWaitForAsyncOperation(openOperation, &contentStream);
|
||||
if (FAILED(hr) || !contentStream) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStream>* FF_AUTO_RELEASE_COM_OBJECT randomAccessStream = NULL;
|
||||
hr = ffQueryInterface<winrt::Windows::Storage::Streams::IRandomAccessStream>(contentStream, &randomAccessStream);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
UINT64 size = 0;
|
||||
hr = randomAccessStream->get_Size(&size);
|
||||
if (FAILED(hr) || size == 0) {
|
||||
return FAILED(hr) ? hr : S_FALSE;
|
||||
}
|
||||
|
||||
if (size > 0xFFFFFFFFu) {
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBufferFactory>* FF_AUTO_RELEASE_COM_OBJECT bufferFactory = NULL;
|
||||
hr = ffGetActivationFactory(L"Windows.Storage.Streams.Buffer", winrt::guid_of<winrt::Windows::Storage::Streams::IBufferFactory>(), &bufferFactory);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBuffer>* FF_AUTO_RELEASE_COM_OBJECT buffer = NULL;
|
||||
hr = bufferFactory->Create((UINT32) size, reinterpret_cast<void**>(&buffer));
|
||||
if (FAILED(hr) || !buffer) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IInputStream>* FF_AUTO_RELEASE_COM_OBJECT inputStream = NULL;
|
||||
hr = ffQueryInterface<winrt::Windows::Storage::Streams::IInputStream>(contentStream, &inputStream);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<IAsyncOperationWithProgress<winrt::Windows::Storage::Streams::IBuffer, uint32_t>>* FF_AUTO_RELEASE_COM_OBJECT readOperation = NULL;
|
||||
hr = inputStream->ReadAsync(buffer, (UINT32) size, static_cast<uint32_t>(winrt::Windows::Storage::Streams::InputStreamOptions::None), reinterpret_cast<void**>(&readOperation));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBuffer>* FF_AUTO_RELEASE_COM_OBJECT readBuffer = NULL;
|
||||
hr = ffWaitForAsyncOperation(readOperation, &readBuffer);
|
||||
if (FAILED(hr) || !readBuffer) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
UINT32 length = 0;
|
||||
hr = readBuffer->get_Length(&length);
|
||||
if (FAILED(hr) || length == 0) {
|
||||
return FAILED(hr) ? hr : S_FALSE;
|
||||
}
|
||||
|
||||
Windows::Storage::Streams::IBufferByteAccess* FF_AUTO_RELEASE_COM_OBJECT byteAccess = NULL;
|
||||
hr = reinterpret_cast<IUnknown*>(readBuffer)->QueryInterface(IID_PPV_ARGS(&byteAccess));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
byte* bytes = NULL;
|
||||
hr = byteAccess->Buffer(&bytes);
|
||||
if (FAILED(hr) || !bytes) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
wchar_t tempDirectory[MAX_PATH];
|
||||
DWORD tempLength = GetTempPathW(MAX_PATH, tempDirectory);
|
||||
if (tempLength == 0 || tempLength >= MAX_PATH) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
wchar_t tempFilePath[MAX_PATH];
|
||||
if (!GetTempFileNameW(tempDirectory, L"fft", 0, tempFilePath)) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
HANDLE file = CreateFileW(tempFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
DeleteFileW(tempFilePath);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
DWORD written = 0;
|
||||
BOOL writtenOk = WriteFile(file, bytes, length, &written, NULL);
|
||||
DWORD writeError = writtenOk ? ERROR_SUCCESS : GetLastError();
|
||||
CloseHandle(file);
|
||||
|
||||
if (!writtenOk || written != length) {
|
||||
DeleteFileW(tempFilePath);
|
||||
return HRESULT_FROM_WIN32(writtenOk ? ERROR_WRITE_FAULT : writeError);
|
||||
}
|
||||
|
||||
ffStrbufSetWS(destination, tempFilePath);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
||||
// RO_INIT_MULTITHREADED is required for IRandomAccessStreamReference::OpenReadAsync to work correctly
|
||||
HRESULT initHr = RoInitialize(RO_INIT_MULTITHREADED);
|
||||
bool shouldUninitialize = SUCCEEDED(initHr);
|
||||
if (FAILED(initHr) && initHr != RPC_E_CHANGED_MODE) {
|
||||
return "winrt: RoInitialize() failed";
|
||||
}
|
||||
|
||||
const char* error = NULL;
|
||||
|
||||
do {
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>* FF_AUTO_RELEASE_COM_OBJECT managerStatics = NULL;
|
||||
HRESULT hr = ffGetActivationFactory(L"Windows.Media.Control.GlobalSystemMediaTransportControlsSessionManager", winrt::guid_of<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>(), &managerStatics);
|
||||
if (FAILED(hr) || !managerStatics) {
|
||||
error = "winrt: RoGetActivationFactory(GlobalSystemMediaTransportControlsSessionManager) failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<IAsyncOperation<winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager>>* FF_AUTO_RELEASE_COM_OBJECT managerOperation = NULL;
|
||||
hr = managerStatics->RequestAsync(reinterpret_cast<void**>(&managerOperation));
|
||||
if (FAILED(hr) || !managerOperation) {
|
||||
error = "winrt: RequestAsync() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManager>* FF_AUTO_RELEASE_COM_OBJECT manager = NULL;
|
||||
hr = ffWaitForAsyncOperation(managerOperation, &manager);
|
||||
if (FAILED(hr) || !manager) {
|
||||
error = "winrt: RequestAsync().GetResults() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSession>* FF_AUTO_RELEASE_COM_OBJECT session = NULL;
|
||||
hr = manager->GetCurrentSession(reinterpret_cast<void**>(&session));
|
||||
if (FAILED(hr) || !session) {
|
||||
error = "winrt: GetCurrentSession() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<IAsyncOperation<winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionMediaProperties>>* FF_AUTO_RELEASE_COM_OBJECT mediaPropsOperation = NULL;
|
||||
hr = session->TryGetMediaPropertiesAsync(reinterpret_cast<void**>(&mediaPropsOperation));
|
||||
if (FAILED(hr) || !mediaPropsOperation) {
|
||||
error = "winrt: TryGetMediaPropertiesAsync() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionMediaProperties>* FF_AUTO_RELEASE_COM_OBJECT mediaProps = NULL;
|
||||
hr = ffWaitForAsyncOperation(mediaPropsOperation, &mediaProps);
|
||||
if (FAILED(hr) || !mediaProps) {
|
||||
error = "winrt: TryGetMediaPropertiesAsync().GetResults() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionPlaybackInfo>* FF_AUTO_RELEASE_COM_OBJECT playbackInfo = NULL;
|
||||
hr = session->GetPlaybackInfo(reinterpret_cast<void**>(&playbackInfo));
|
||||
if (SUCCEEDED(hr) && playbackInfo) {
|
||||
int32_t playbackStatusValue = 0;
|
||||
if (SUCCEEDED(playbackInfo->get_PlaybackStatus(&playbackStatusValue))) {
|
||||
switch (static_cast<winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionPlaybackStatus>(playbackStatusValue)) {
|
||||
#define FF_MEDIA_SET_STATUS(status_code) \
|
||||
case winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: \
|
||||
ffStrbufSetStatic(&result->status, #status_code); \
|
||||
break;
|
||||
FF_MEDIA_SET_STATUS(Closed)
|
||||
FF_MEDIA_SET_STATUS(Opened)
|
||||
FF_MEDIA_SET_STATUS(Changing)
|
||||
FF_MEDIA_SET_STATUS(Stopped)
|
||||
FF_MEDIA_SET_STATUS(Playing)
|
||||
FF_MEDIA_SET_STATUS(Paused)
|
||||
#undef FF_MEDIA_SET_STATUS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING playerId = NULL;
|
||||
hr = session->get_SourceAppUserModelId(reinterpret_cast<void**>(&playerId));
|
||||
if (FAILED(hr)) {
|
||||
error = "winrt: get_SourceAppUserModelId() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
ffStrbufSetHstring(&result->playerId, playerId);
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING title = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_Title(reinterpret_cast<void**>(&title)))) {
|
||||
ffStrbufSetHstring(&result->song, title);
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING artist = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_Artist(reinterpret_cast<void**>(&artist)))) {
|
||||
ffStrbufSetHstring(&result->artist, artist);
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING album = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_AlbumTitle(reinterpret_cast<void**>(&album)))) {
|
||||
ffStrbufSetHstring(&result->album, album);
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppInfoStatics>* FF_AUTO_RELEASE_COM_OBJECT appInfoStatics = NULL;
|
||||
hr = ffGetActivationFactory(L"Windows.ApplicationModel.AppInfo", winrt::guid_of<winrt::Windows::ApplicationModel::IAppInfoStatics>(), &appInfoStatics);
|
||||
if (SUCCEEDED(hr) && appInfoStatics) {
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppInfo>* FF_AUTO_RELEASE_COM_OBJECT appInfo = NULL;
|
||||
if (SUCCEEDED(appInfoStatics->GetFromAppUserModelId(reinterpret_cast<void*>(playerId), reinterpret_cast<void**>(&appInfo))) && appInfo) {
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppDisplayInfo>* FF_AUTO_RELEASE_COM_OBJECT displayInfo = NULL;
|
||||
if (SUCCEEDED(appInfo->get_DisplayInfo(reinterpret_cast<void**>(&displayInfo))) && displayInfo) {
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING displayName = NULL;
|
||||
if (SUCCEEDED(displayInfo->get_DisplayName(reinterpret_cast<void**>(&displayName)))) {
|
||||
ffStrbufSetHstring(&result->player, displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result->player.length == 0) {
|
||||
ffStrbufSet(&result->player, &result->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&result->player, ".exe")) {
|
||||
ffStrbufSubstrBefore(&result->player, result->player.length - 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (saveCover) {
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* FF_AUTO_RELEASE_COM_OBJECT thumbnail = NULL;
|
||||
hr = mediaProps->get_Thumbnail(reinterpret_cast<void**>(&thumbnail));
|
||||
if (SUCCEEDED(hr) && thumbnail) {
|
||||
if (SUCCEEDED(ffSaveThumbnailToTempPath(thumbnail, &result->cover)) && result->cover.length > 0) {
|
||||
result->removeCoverAfterUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
if (shouldUninitialize) {
|
||||
RoUninitialize();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#else
|
||||
static const char* getMedia(FFMediaResult* media, bool saveCover) {
|
||||
FF_UNUSED(media, saveCover);
|
||||
return "Fastfetch is not compiled with WinRT support";
|
||||
}
|
||||
#endif // FF_HAVE_WINRT
|
||||
|
||||
extern "C" void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
|
||||
const char* error = getMedia(media, saveCover);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#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 <windows.h>
|
||||
|
||||
extern "C" {
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
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;
|
||||
|
||||
try {
|
||||
auto manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().get();
|
||||
if (!manager) {
|
||||
return "winrt: GlobalSystemMediaTransportControlsSessionManager::RequestAsync() failed";
|
||||
}
|
||||
|
||||
auto session = manager.GetCurrentSession();
|
||||
if (!session) {
|
||||
return "winrt: GetCurrentSession() failed";
|
||||
}
|
||||
|
||||
auto mediaProps = session
|
||||
.TryGetMediaPropertiesAsync()
|
||||
.get();
|
||||
if (!mediaProps) {
|
||||
return "winrt: TryGetMediaPropertiesAsync() failed";
|
||||
}
|
||||
|
||||
if (auto playbackInfo = session.GetPlaybackInfo()) {
|
||||
switch (playbackInfo.PlaybackStatus()) {
|
||||
#define FF_MEDIA_SET_STATUS(status_code) \
|
||||
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: \
|
||||
result->status = #status_code; \
|
||||
break;
|
||||
FF_MEDIA_SET_STATUS(Closed)
|
||||
FF_MEDIA_SET_STATUS(Opened)
|
||||
FF_MEDIA_SET_STATUS(Changing)
|
||||
FF_MEDIA_SET_STATUS(Stopped)
|
||||
FF_MEDIA_SET_STATUS(Playing)
|
||||
FF_MEDIA_SET_STATUS(Paused)
|
||||
#undef FF_MEDIA_SET_STATUS
|
||||
}
|
||||
}
|
||||
|
||||
::wcsncpy(result->playerId, session.SourceAppUserModelId().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->playerId[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->song[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->artist[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->album[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
try {
|
||||
// Only works for UWP apps
|
||||
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->playerName[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
} catch (...) {}
|
||||
|
||||
if (saveCover) {
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt::Windows::Storage::Streams;
|
||||
if (auto thumbRef = mediaProps.Thumbnail()) {
|
||||
try {
|
||||
if (auto stream = thumbRef.OpenReadAsync().get()) {
|
||||
if (stream.Size() > 0) {
|
||||
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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} catch (...) {
|
||||
return "A C++ exception is thrown";
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define FF_MEDIA_WIN_RESULT_BUFLEN 256
|
||||
|
||||
typedef struct FFWinrtMediaResult {
|
||||
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
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;
|
||||
} FFWinrtMediaResult;
|
||||
|
||||
__attribute__((__dllexport__))
|
||||
const char*
|
||||
ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover);
|
||||
Reference in New Issue
Block a user