☰
YASB Media Widget 配置完全指南:打造可滚动标签与弹出播放器的媒体状态栏控件
2026/10/12 1:53:20 网站建设 项目流程
  • 桌面应用

【免费下载链接】yasb

A highly configurable Windows status bar written in Python.

项目地址:https://gitcode.com/gh_mirrors/yas/yasb
点击查看免费下载

导读

Media Widget 是 YASB(一个用 Python 编写的 Windows 状态栏)中用于展示“正在播放”信息的核心小组件:它能在任务栏上显示当前播放的歌曲或视频标题、艺术家与专辑封面,内置上一曲 / 播放暂停 / 下一曲按钮,支持超长标题滚动,并可弹出包含进度条、时间标签、来源应用与逐应用音量滑杆的播放控制菜单。本文以官方文档为主体,结合仓库源码(widget 实现、校验模型、SMTC 媒体服务)逐一讲解全部配置项、默认值与底层工作原理,读完你可以独立完成 Media Widget 的接入、外观定制与故障排查。

图片预览:下图为 Media Widget 在状态栏上的实际呈现(来源:文档原图)。

一、组件能力与数据来源

Media Widget 是一个“播放器控制控件”,它展示当前正在播放的歌曲或视频,并具备以下能力:

  • 显示专辑封面(缩略图),支持透明度、圆角、边缘渐隐等效果;
  • 内联媒体按钮:上一曲(prev_track)、播放 / 暂停(play/pause)、下一曲(next_track);
  • 超长标题滚动(scrolling_label);
  • 弹出媒体菜单(popup):包含封面大图、标题 / 艺术家 / 来源应用、进度滑块、播放时间与逐应用音量控制。

它的数据来自 Windows 系统的SMTC(Global System Media Transport Controls)。在源码中,WindowsMedia是一个以QSingleton实现的单例服务(src/core/widgets/services/media/media.py),通过winrt.windows.media.control的GlobalSystemMediaTransportControlsSessionManager请求会话、订阅会话列表变化 / 当前会话变化 / 媒体属性 / 时间线 / 播放信息五类事件,并以约 0.1 秒(REFRESH_INTERVAL = 0.1)的轮询间隔插值当前播放位置(_interpolate_and_emit),再把状态通过 Qt 信号分发给 Widget。

重要限制(原文保留):时间线与 seek 功能只有在播放器通过 Windows 媒体 API 上报 position 和 duration 时才会生效。很多浏览器和部分应用不上报,或上报的是无效值,因此 seek 滑块可能会保持禁用、跳动或完全不动。YASB 只展示系统给到的数据——如果来源应用没有暴露可用的时间线,Widget 也无能为力。

此外源码中还有一层保护:MAX_TIMLINE_DURATION = 604800(7 天)——当会话时长超过 7 天或时间线不可用时,进度条与时间线容器会被隐藏(见 media.py 及show_menu中的判断逻辑)。

二、完整配置项总览

将media段写入 YASB 的config.yaml(位于C:/Users/{username}/.config/yasb/或YASB_CONFIG_HOME指定的目录,详见 Configuration.md),type固定为"yasb.media.MediaWidget"。

选项类型默认值(文档)说明
labelstring"{artist}{s}{title}"主标签格式字符串。
label_altstring"{title}"备用标签格式字符串。
separatorstring" - "动态分隔符{s}的实际文本;位于标签开头或结尾时会被自动剥离,详见下文。
class_namestring""附加到组件上的自定义 CSS 类名。
max_field_sizedict—标签最大字段长度。
max_field_size.labelinteger20主标签最大长度。
max_field_size.label_altinteger30备用标签最大长度。
max_field_size.truncate_whole_labelbooleanfalse超长时是否截断整个标签(而不是只截断超出的字段)。
show_thumbnailbooleantrue是否显示媒体缩略图。
controls_onlybooleanfalse是否只显示媒体控制按钮。
controls_leftbooleantrue控制按钮是否位于左侧。
controls_hidebooleanfalse是否隐藏媒体控制按钮。
hide_emptybooleantrue无媒体信息时是否隐藏整个组件。
thumbnail_alphainteger50缩略图的透明度(alpha)。
thumbnail_paddinginteger8缩略图周围的内边距。
thumbnail_corner_radiusinteger0缩略图圆角半径,0 为直角。
symmetric_corner_radiusbooleanfalse是否对缩略图四角使用对称圆角。
thumbnail_edge_fadebooleanfalse是否对缩略图应用边缘渐隐效果。
iconsdict—媒体控制按钮图标。
icons.prev_trackstring\uf048上一曲按钮图标。
icons.next_trackstring\uf051下一曲按钮图标。
icons.playstring\uf04b播放按钮图标。
icons.pausestring\uf04c暂停按钮图标。
media_menudict见下媒体菜单(弹出层)配置。
media_menu_iconsdict见下媒体菜单中的图标配置。
scrolling_labeldict见下标签滚动配置。
progress_bardict见下组件内嵌进度条配置。
callbacksdict见下鼠标事件回调。

源码校验模型中的真实默认值

文档表格中的“默认值”对应官方推荐预设;代码层面真正的默认值由 Pydantic 校验模型定义(src/core/validation/widgets/yasb/media.py),两者不完全一致,配置时以你显式写入的值优先:

  • label默认为"{title}",label_alt默认为"{artist} - {title}"(文档表分别为{artist}{s}{title}与{title});
  • hide_empty默认False(文档表为true);
  • max_field_size.label默认15(取值范围 0–200),truncate_whole_label默认True;
  • thumbnail_alpha取值范围0–255;thumbnail_padding取值范围0–200;thumbnail_corner_radius取值范围0–100;
  • media_menu默认blur=True、round_corners=True、border_color="System"、alignment="right"、thumbnail_size=100、max_title_size=150、max_artist_size=40、max_source_size=16;
  • scrolling_label.update_interval_ms默认 33(代码内会被钳制在 4–1000ms),style默认"left",separator默认空格;
  • progress_bar.enabled默认False,alignment默认"bottom"。

官方安装向导预设(src/core/setup/widgets_config.py)中,Media Widget 使用label: "{title}{s}{artist}"、hide_empty: True、controls_hide: True、thumbnail_alpha: 100、thumbnail_edge_fade: True、media_menu.alignment: "center"且show_volume_slider: True,可作为一份开箱即用的参考配置。

三、示例配置(可直接复制)

media: type: "yasb.media.MediaWidget" options: label: "{title}{s}{artist}" label_alt: "{title}" separator: " - " hide_empty: true callbacks: on_left: "toggle_label" on_middle: "do_nothing" on_right: "do_nothing" max_field_size: label: 20 label_alt: 30 show_thumbnail: true controls_only: false controls_left: true controls_hide: false thumbnail_alpha: 80 thumbnail_padding: 8 thumbnail_corner_radius: 16 icons: prev_track: "\ue892" next_track: "\ue893" play: "\ue768" pause: "\ue769" media_menu: blur: false round_corners: true round_corners_type: "normal" border_color: "system" alignment: "right" direction: "down" offset_top: 6 offset_left: 0 thumbnail_corner_radius: 8 thumbnail_size: 120 max_title_size: 60 max_artist_size: 20 max_source_size: 16 show_source: true show_volume_slider: true media_menu_icons: play: "\ue768" pause: "\ue769" prev_track: "\ue892" next_track: "\ue893" scrolling_label: enabled: false update_interval_ms: 33 style: "left" # 可选 "left"、"right"、"bounce"、"bounce-ease" separator: " | " label_padding: 0 always_scroll: false # 缓动曲线参数参考:https://www.desmos.com/calculator/j7eamemxzi ease_slope: 20 ease_pos: 0.8 ease_min: 0.5

在状态栏的widgets段(left/center/right任一区)中引用该段即可启用,例如:

bars: bar: widgets: right: ["media"]

四、各子配置项详解

4.1 标签与字段(label / label_alt / separator / max_field_size)

  • label / label_alt:格式字符串,可用{title}、{artist}等占位符动态插入媒体信息;label_alt用于展示补充信息,通常配合toggle_label回调在两条标签间切换。
  • separator 与{s}:{s}是动态分隔符占位符。当某段信息在来源端缺失时,为避免标签首尾残留悬空分隔符(如" - - 歌名"),Widget 会调用分词器 tokenizer.py 的clean_string:先按{占位符} / 字面量分词,再丢弃值为空的占位符,最后只保留“前后都有非空占位符”的分隔符。这就是文档所说“动态分隔符会被自动剥离”的实现原理。
  • max_field_size:label/label_alt为对应标签的最大字符数,超长时截断并追加...(见_format_max_field_size,截断方式为text[:max_size - 3] + "...");truncate_whole_label: true时对整条格式化结果截断,否则仅截断单个超长字段。注意:启用scrolling_label后,_format_max_field_size会直接返回原文(滚动标签自身依赖max_field_size.label作为宽度上限)。

4.2 缩略图(show_thumbnail 与视觉处理)

缩略图在 media.py 的_crop_thumbnail中按以下流程处理:

  1. 按thumbnail_padding与当前活动标签宽度等比缩放(Image.LANCZOS高质量重采样);
  2. 按组件容器高度纵向居中裁剪;
  3. 用thumbnail_alpha值构造 alpha 通道;
  4. 若启用thumbnail_edge_fade,则对 alpha 通道应用左右两侧约 30% 宽度的渐隐(与容器背景形成平滑过渡,此时圆角不生效);
  5. 否则当thumbnail_corner_radius > 0时生成圆角遮罩——默认只圆“靠近按钮的对侧”两角(controls_left: true时圆右侧两角),symmetric_corner_radius: true时四角统一圆角。

另外,当会话没有封面时,popup 会回退到内置的 media.png 占位图(_build_empty_thumbnail)。

4.3 控制按钮(controls_only / controls_left / controls_hide / icons)

  • 三个按钮按controls_left决定排在缩略图与文本的左侧还是右侧;controls_only: true时隐藏标签、缩略图与进度条,只保留按钮(源码中会hide()对应控件)。
  • controls_hide: true时完全不创建按钮(_create_media_button直接返回None),适合只需要信息展示的场景。
  • 按钮的可用 / 禁用状态来自 SMTC 的PlaybackInfo快照字段(controls_prev_enabled/controls_play_enabled/controls_next_enabled),不可用时按钮会带上disabledCSS 类。
  • 播放 / 暂停按钮图标会根据is_playing在icons.play与icons.pause间切换(同一逻辑也作用于 popup 的media_menu_icons)。

4.4 媒体菜单(media_menu)

弹出层由工具类PopupWidget(src/core/utils/utilities.py)创建:无边框、置顶、支持背景模糊(acrylic)、圆角与边框色;setPosition按alignment(left / center / right)、direction(up / down)、offset_top/offset_left相对父组件定位。菜单内容在show_menu中动态构建:

  • 左侧为按thumbnail_size裁剪成方形的封面大图(_create_thumbnail_for_popup),可点击唤起来源应用(_open_media_source);
  • 右侧文本区包含max_title_size/max_artist_size限制的标题与艺术家;
  • 控制区含上一曲 / 播放暂停 / 下一曲按钮,以及show_source: true时的来源应用标签;
  • 底部为时间线容器:progress-slider(内部精度 0–1000)加playback-time.current/playback-time.total两个时间标签;用户拖动时通过_on_slider_released把百分比换算成秒,并以 100 纳秒为单位调用try_change_playback_position_async完成 seek;
  • show_volume_slider: true时右侧会出现“逐应用音量”竖滑杆:先用会话的 AUMID 通过pycaw的AudioUtilities.GetAllSessions()匹配音频会话(优先按 AUMID,失败则回退按进程可执行文件名),再用SimpleAudioVolume接口读取 / 设置音量并切换静音(对应mute/unmute图标)。
  • 无任何会话时,菜单显示no-media类的“No media playing”占位文案。
  • 在组件与 popup 上滚动鼠标滚轮可在多个媒体会话间切换(WheelEventFilter,向上滚下一个、向下滚上一个)。
media_menu: blur: false # 是否对弹出背景应用模糊效果。 round_corners: true # 是否圆角弹出层。 round_corners_type: "normal" # "normal" 或 "small"(仅 Win11) border_color: "system" # 弹出层边框颜色,可为 HEX、None 或 "system"。 alignment: "right" # 相对组件的对齐方式:"left"、"center" 或 "right"。 direction: "down" # 弹出方向:"up" 或 "down"。 offset_top: 6 # 距组件的垂直偏移。 offset_left: 0 # 距组件的水平偏移。 thumbnail_corner_radius: 8 # 弹出层封面的圆角半径。 thumbnail_size: 120 # 弹出层封面尺寸。 max_title_size: 60 # 弹出层标题最大长度。 max_artist_size: 20 # 弹出层艺术家最大长度。 max_source_size: 16 # 弹出层来源应用名最大长度。 show_source: true # 是否显示媒体来源应用名(由系统/应用元数据解析,如 Spotify、Firefox)。 show_volume_slider: false # 是否显示逐应用音量滑杆。

4.5 媒体菜单图标(media_menu_icons)

media_menu_icons: play: "\ue768" # 弹出层播放按钮图标。 pause: "\ue769" # 弹出层暂停按钮图标。 prev_track: "\ue892" # 弹出层上一曲按钮图标。 next_track: "\ue893" # 弹出层下一曲按钮图标。 mute: "\ue994" # 弹出层静音按钮图标。 unmute: "\ue74f" # 弹出层取消静音按钮图标。

4.6 滚动标签(scrolling_label)

滚动能力来自工具类ScrollingLabel(src/core/utils/utilities.py),支持四种style:

  • left/right:循环平移滚动,超出部分用separator拼接重复文本,always_scroll: true时无论文本是否超宽都滚动;
  • bounce:来回弹跳,两侧各留label_padding个字符的边距;
  • bounce-ease:带缓动的弹跳,速度由ease_slope(坡度)、ease_pos(拐点位置)、ease_min(最小速度比例)三条参数控制,公式为(1 + tanh(-slope·(x - pos)))·(1 - min)/2 + min,可通过 Desmos 交互曲线直观调参。
scrolling_label: enabled: false # 是否启用滚动标签。 update_interval_ms: 33 # 滚动更新间隔(毫秒),有效范围 4–1000。 style: "left" # 滚动样式:"left"、"right"、"bounce" 或 "bounce-ease"。 separator: " | " # "left"/"right" 样式中重复文本间的分隔符。 label_padding: 1 # "bounce"/"bounce-ease" 样式两侧的填充字符数,默认各 1 个字符。 ease_slope: 20 # bounce 缓动坡度。缓动曲线参考:https://www.desmos.com/calculator/j7eamemxzi ease_pos: 0.8 # bounce 缓动曲线位置。 ease_min: 0.5 # bounce 缓动曲线的最小值。

滚动标签注意事项(原文保留):

  • 滚动标签使用max_field_size限制自身尺寸;
  • 滚动标签会禁用thumbnail_padding,此时应改用.media-widget .label { margin: ... }控制间距。

4.7 组件内嵌进度条(progress_bar)

在组件本身(而非 popup)底部叠加一层细进度条,指示当前播放进度;只有当会话启用时间线且时长在 7 天以内时才显示。alignment控制它在容器内的垂直位置。

progress_bar: enabled: false # 是否启用组件上的进度条。 alignment: "bottom" # 进度条在组件容器内的对齐方式:"top"、"bottom" 或 "center"。

4.8 可用回调(callbacks)

回调说明
toggle_label在主标签与备用标签间切换显示。
toggle_play_pause切换播放 / 暂停状态。
toggle_media_menu打开 / 关闭媒体菜单弹出层。
open_media_source打开正在播放媒体的来源应用(按 AUMID 激活)。
do_nothing占位回调,触发时不做任何事。

callbacks的键为on_left、on_middle、on_right,分别绑定左 / 中 / 右键。源码细节:toggle_label仅在非controls_only模式下注册;open_media_source通过activate_app_by_aumid激活会话(见 media.py)。

五、来源应用名的解析与“按来源定制样式”

popup 中的source标签显示来源应用名,其解析链在 source_apps.py 中定义,按优先级依次尝试:

  1. AppInfo.get_from_app_user_model_id(aumid)的display_name;
  2. shell:AppsFolder的ParseName名称(保证 PWA 不被错误标记为浏览器);
  3. 由 AUMID 反查进程可执行文件,再取进程的FileDescription;
  4. 由窗口 AUMID(Firefox / Zen 等哈希)反查 PID 得到应用名;
  5. 最后退化为_humanize(去掉扩展名、取!后段、下划线转空格等)。

解析结果会按 AUMID 缓存。而get_source_app_class_name会把显示名转为小写并将空格替换为连字符——因此样式表中“来源类名”与组件中看到的来源名一一对应:例如"Windows Media"对应.source.windows-media。这意味着你可以为每个播放器定制专属配色(见下文示例中的.media-menu .source.spotify、.source.chrome等)。

六、样式定制(CSS Classes)

Widget 渲染为 Qt Widgets,可使用 Qt 样式表(qss)定制外观,整体主题样式相关约定见 Styling.md。

6.1 可用样式类

.media-widget {} .media-widget .widget-container {} .media-widget .label {} .media-widget .label.alt {} .media-widget .btn.play {} .media-widget .btn.prev {} .media-widget .btn.next {} .media-widget .btn.disabled {} .media-widget .progress-bar { } .media-widget .progress-bar::chunk {} .media-menu {} .media-menu .no-media {} .media-menu .title {} .media-menu .artist {} .media-menu .source {} .media-menu .btn.play {} .media-menu .btn.prev {} .media-menu .btn.next {} .media-menu .btn.disabled {} .media-menu .thumbnail {} .media-menu .media-timeline-container {} .media-menu .playback-time {} .media-menu .playback-time.current {} .media-menu .playback-time.total {} .media-menu .progress-slider {} .media-menu .progress-slider::groove {} .media-menu .progress-slider::sub-page {} .media-menu .progress-slider::handle {} .media-menu .progress-slider::handle:hover {} .media-menu .app-volume-container {} .media-menu .app-volume-container .volume-slider {} .media-menu .app-volume-container .volume-slider::groove {} .media-menu .app-volume-container .volume-slider::sub-page {} .media-menu .app-volume-container .volume-slider::handle {} .media-menu .app-volume-container .volume-slider::handle:hover {} .media-menu .app-volume-container .mute-button {}

6.2 组件样式示例

.media-widget { padding: 0; margin: 0; } .media-widget .label { color: #d2d6e2; padding: 0px; padding-right: 4px; font-size: 12px; } .media-widget .btn { color: #9498a8; padding: 0 4px; margin: 0; font-family: "Segoe Fluent Icons"; font-weight: 400; } .media-widget .btn:hover { color: #babfd3; } .media-widget .btn.play { font-size: 16px; } .media-widget .btn.disabled:hover, .media-widget .btn.disabled { color: #4e525c; font-size: 12px; background-color: rgba(0, 0, 0, 0); } .media-widget .progress-bar { max-height: 2px; background-color: transparent; margin-left: 5px; border: none; } .media-widget .progress-bar::chunk { background-color: #0078D4ee; border-radius: 2px; }

6.3 弹出菜单样式示例

.media-menu { min-width: 440px; max-width: 440px; background-color: rgba(31, 39, 49, 0.5); } .media-menu .title, .media-menu .artist, .media-menu .source { font-size: 14px; font-weight: 600; margin-left: 10px; font-family: 'Segoe UI'; } .media-menu .artist { font-size: 13px; color: #6c7086; margin-top: 0px; } .media-menu .source { font-size: 11px; color: #000; border-radius: 3px; background-color: #bac2de; padding: 2px 4px; font-weight: 600; font-family: 'Segoe UI'; margin-top: 10px; } /* 来源类名的规则与组件中看到的来源名一致:空格换成连字符并转为小写。 示例:"Windows Media" 变成 "windows-media" */ .media-menu .source.aimp { background-color: #6f42c1; color: #ffffff; } .media-menu .source.apple-music { background-color: #fa2b56; color: #ffffff; } .media-menu .source.brave { background-color: #fb542b; color: #ffffff; } .media-menu .source.chrome { background-color: #4285f4; color: #ffffff; } .media-menu .source.edge { background-color: #0078d4; color: #ffffff; } .media-menu .source.firefox { background-color: #ff7139; color: #ffffff; } .media-menu .source.foobar2000 { background-color: #444444; color: #ffffff; } .media-menu .source.media-player { background-color: #0078d4; color: #ffffff; } .media-menu .source.murglar { background-color: #8a8a8a; color: #ffffff; } .media-menu .source.musicbee { background-color: #ffcc00; color: #000000; } .media-menu .source.nsmusics { background-color: #e64a19; color: #ffffff; } .media-menu .source.opera { background-color: #ff1b2d; color: #ffffff; } .media-menu .source.qobuz { background-color: #003a6f; color: #ffffff; } .media-menu .source.spotify { background-color: #1db954; color: #ffffff; } .media-menu .source.tidal { background-color: #000000; color: #ffffff; } .media-menu .source.winamp { background-color: #f1a11b; color: #000000; } .media-menu .source.youtube { background-color: #ff0000; color: #ffffff; } .media-menu .source.youtube-music { background-color: #c51f1f; color: #ffffff; } .media-menu .source.zen { background-color: #2ecc71; color: #000000; } .media-menu .btn { font-family: "Segoe Fluent Icons"; font-size: 14px; font-weight: 400; margin: 10px 2px 0px 2px; min-width: 40px; max-width: 40px; min-height: 40px; max-height: 40px; border-radius: 20px; } .media-menu .btn.prev { margin-left: 10px; } .media-menu .btn:hover { color: white; background-color: rgba(255, 255, 255, 0.1); } .media-menu .btn.play { background-color: rgba(255, 255, 255, 0.1); font-size: 20px } .media-menu .btn.disabled:hover, .media-menu .btn.disabled { color: #4e525c; background-color: rgba(0, 0, 0, 0); } .media-menu .playback-time { font-size: 13px; font-family: 'Segoe UI'; color: #7f849c; margin-top: 20px; min-width: 100px; } .media-menu .progress-slider { height: 10px; margin: 5px 4px; border-radius: 3px; } .media-menu .progress-slider::groove { background: transparent; height: 2px; border-radius: 3px; background: rgba(255, 255, 255, 0.1); } .media-menu .progress-slider::groove:hover { background: transparent; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, 0.2); } .media-menu .progress-slider::sub-page { background: white; border-radius: 3px; height: 4px; } .media-menu .app-volume-container { background-color: rgba(255, 255, 255, 0.05); padding: 8px 6px; border-radius: 16px; margin-left: 10px; } .media-menu .app-volume-container .volume-slider::groove { background: rgba(255, 255, 255, 0.1); width: 2px; border-radius: 3px; } .media-menu .app-volume-container .volume-slider::add-page { background: white; border-radius: 3px; } .media-menu .app-volume-container .volume-slider::groove:hover { background: rgba(255, 255, 255, 0.1); width: 6px; border-radius: 3px; } .media-menu .app-volume-container .volume-slider::sub-page { background: rgba(255, 255, 255, 0.1); border-radius: 3px; } .media-menu .app-volume-container .mute-button, .media-menu .app-volume-container .unmute-button { font-size: 16px; color: #ffffff; font-family: "Segoe Fluent Icons"; margin-top: 4px; } .media-menu .app-volume-container .unmute-button { color: #a0a0a0; }

注意(原文保留):以上样式示例使用 Segoe Fluent Icons 字体作为按钮图标,你也可以按设计需求使用任何其它图标字体或自定义图标。

七、常见调优建议与排错要点

  • 标签不更新 / 按钮灰置:按钮可用状态来自播放器上报的 SMTCPlaybackInfo;如果来源应用不上报,按钮会带disabled类(可用.media-widget .btn.disabled弱化其视觉权重)。
  • seek 滑块不动或跳动:属于来源应用不提供有效时间线的表现,不是配置错误,参见第一节的官方说明。
  • 切换会话:在组件或 popup 上滚动滚轮即可在多个媒体会话(如浏览器标签页、Spotify、本地播放器)间切换;源码中 popup 的WheelEventFilter在切换会话后会重建菜单以同步内容。
  • 想要更精简的竖向“唱片封面风”方案:YASB 还提供同源的media_lite组件("yasb.media_lite.MediaWidget"),支持封面 + 标题/艺术家单行展示与弹出播放器,详见 Media Lite Widget 文档-Media-Lite.md)。
  • 图标字体:示例默认使用"Segoe Fluent Icons";自定义图标时同步修改icons/media_menu_icons与对应字体族即可。
  • 配置校验:所有选项均经过 Pydantic 模型(src/core/validation/widgets/yasb/media.py)校验,非法取值(如越界的thumbnail_alpha、非法style枚举)会在启动时报错,修改配置后保存会自动重载(见 watcher.py 的文件监听机制)。
  • 桌面应用

【免费下载链接】yasb

A highly configurable Windows status bar written in Python.

项目地址:https://gitcode.com/gh_mirrors/yas/yasb
点击查看免费下载
上一篇:VisualCppRedist AIO:一站式解决Windows软件运行库依赖难题
下一篇:Apache Beam PTransform 风格指南:编写可复用 Transform 的完整设计规范与仓库源码实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询