ohmu
·
2026-10-15
1#include "common/printing.h"
2#include "common/jsonconfig.h"
3#include "common/strutil.h"
4#include "detection/media/media.h"
5#include "modules/player/player.h"
6
7#include <ctype.h>
8
9bool ffPrintPlayer(FFPlayerOptions* options) {
10 const FFMediaResult* media = ffDetectMedia(false);
11
12 if (media->error.length > 0) {
13 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Player), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", media->error.chars);
14 return false;
15 }
16
17 if (media->player.length == 0) {
18 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Player), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No media player detected");
19 return false;
20 }
21
22 FF_STRBUF_AUTO_DESTROY playerPretty = ffStrbufCreate();
23
24 if (media->url.length > 0) {
25 // If we are on a website, prepend the website name
26 if (
27 ffStrbufIgnCaseEqualS(&media->playerId, "spotify") ||
28 ffStrbufIgnCaseEqualS(&media->playerId, "vlc")) {
29 } // do noting, surely not a website, even if the url is set
30 else if (ffStrbufStartsWithS(&media->url, "https://www.")) {
31 ffStrbufAppendS(&playerPretty, media->url.chars + 12);
32 } else if (ffStrbufStartsWithS(&media->url, "http://www.")) {
33 ffStrbufAppendS(&playerPretty, media->url.chars + 11);
34 } else if (ffStrbufStartsWithS(&media->url, "https://")) {
35 ffStrbufAppendS(&playerPretty, media->url.chars + 8);
36 } else if (ffStrbufStartsWithS(&media->url, "http://")) {
37 ffStrbufAppendS(&playerPretty, media->url.chars + 7);
38 }
39 }
40
41 // If we found a website name, make it more pretty
42 if (playerPretty.length > 0) {
43 ffStrbufSubstrBeforeFirstC(&playerPretty, '/'); // Remove the path
44 ffStrbufSubstrBeforeLastC(&playerPretty, '.'); // Remove the TLD
45 }
46
47 // Check again for length, as we may have removed everything.
48 bool playerPrettyIsCustom = playerPretty.length > 0;
49
50 // If we don't have subdomains, it is usually more pretty to capitalize the first letter.
51 if (playerPrettyIsCustom && ffStrbufFirstIndexC(&playerPretty, '.') == playerPretty.length) {
52 playerPretty.chars[0] = (char) toupper(playerPretty.chars[0]);
53 }
54
55 if (playerPrettyIsCustom) {
56 ffStrbufAppendS(&playerPretty, " (");
57 }
58
59 ffStrbufAppend(&playerPretty, &media->player);
60
61 if (playerPrettyIsCustom) {
62 ffStrbufAppendC(&playerPretty, ')');
63 }
64
65 if (options->moduleArgs.outputFormat.length == 0) {
66 ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Player), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
67 ffStrbufPutTo(&playerPretty, stdout);
68 } else {
69 FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Player), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
70 FF_ARG(playerPretty, "player"),
71 FF_ARG(media->player, "name"),
72 FF_ARG(media->playerId, "id"),
73 FF_ARG(media->url, "url"),
74 }));
75 }
76
77 return true;
78}
79
80void ffParsePlayerJsonObject(FFPlayerOptions* options, yyjson_val* module) {
81 yyjson_val *key, *val;
82 size_t idx, max;
83 yyjson_obj_foreach (module, idx, max, key, val) {
84 if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
85 continue;
86 }
87
88 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Player), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
89 }
90}
91
92[[gnu::cold]]
93void ffGeneratePlayerJsonConfig(FFPlayerOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
94 ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
95}
96
97bool ffGeneratePlayerJsonResult([[maybe_unused]] FFMediaOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
98 yyjson_mut_obj_add_str(doc, module, "error", "Player module is an alias of Media module");
99 return false;
100}
101
102void ffInitPlayerOptions(FFPlayerOptions* options) {
103 ffOptionInitModuleArg(&options->moduleArgs, "");
104}
105
106void ffDestroyPlayerOptions(FFPlayerOptions* options) {
107 ffOptionDestroyModuleArg(&options->moduleArgs);
108}
109
110FFModuleBaseInfo ffPlayerModuleInfo = {
111 .name = "Player",
112 .description = "Print the music player name that is currently active",
113 .displayName = {
114 .en = "Media Player",
115 .ar = "مشغل الوسائط",
116 .cs = "Přehrávač médií",
117 .de = "Medienplayer",
118 .es = "Reproductor multimedia",
119 .fi = "Mediasoitin",
120 .fr = "Lecteur multimédia",
121 .gl = "Reprodutor multimedia",
122 .he = "נגן מדיה",
123 .id = "Pemutar Media",
124 .it = "Lettore multimediale",
125 .ja = "メディアプレイヤー",
126 .ko = "미디어 플레이어",
127 .pl = "Odtwarzacz multimediów",
128 .pt = "Reprodutor de mídia",
129 .ru = "Медиаплеер",
130 .tr = "Medya Oynatıcı",
131 .uk = "Медіаплеєр",
132 .vi = "Trình phát phương tiện",
133 .zh_CN = "媒体播放器",
134 .zh_TW = "媒體播放器",
135 },
136 .initOptions = (void*) ffInitPlayerOptions,
137 .destroyOptions = (void*) ffDestroyPlayerOptions,
138 .parseJsonObject = (void*) ffParsePlayerJsonObject,
139 .printModule = (void*) ffPrintPlayer,
140 .generateJsonResult = (void*) ffGeneratePlayerJsonResult,
141 .generateJsonConfig = (void*) ffGeneratePlayerJsonConfig,
142 .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
143 { "Pretty player name", "player" },
144 { "Player name", "name" },
145 { "Player Identifier", "id" },
146 { "URL name", "url" },
147 })),
148 .defaultOrder = 47,
149};