Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package spicetify-cli for openSUSE:Factory checked in at 2025-03-13 15:07:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/spicetify-cli (Old) and /work/SRC/openSUSE:Factory/.spicetify-cli.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "spicetify-cli" Thu Mar 13 15:07:58 2025 rev:9 rq:1252741 version:2.39.5 Changes: -------- --- /work/SRC/openSUSE:Factory/spicetify-cli/spicetify-cli.changes 2025-02-16 22:50:20.796594975 +0100 +++ /work/SRC/openSUSE:Factory/.spicetify-cli.new.19136/spicetify-cli.changes 2025-03-13 15:08:40.348428866 +0100 @@ -1,0 +2,14 @@ +Thu Mar 13 11:23:58 UTC 2025 - jan.kuzi...@suse.com + +- Update to version 2.39.5: + * fix: remove bypass flag after checking for admin + * fix(popupLyrics): update view in system tray mode (#3330) + * feat(types): add `dark_vibrant` to `colorExtractor` (#3321) + * feat(popupLyrics): implement lyrics caching & Musixmatch token refresh (#3328) + * style: run `fmt` on `isAdmin` pkg + * fix: split `isAdmin` to platform files + * fix(preprocess): add css for height on apps pages (1.2.57+) + * feat: disallow running spicetify as admin/root + * fix(lyrics-plus): properly set height on main view (#3322) + +------------------------------------------------------------------- Old: ---- cli-2.39.3.obscpio New: ---- cli-2.39.5.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ spicetify-cli.spec ++++++ --- /var/tmp/diff_new_pack.uK3rm8/_old 2025-03-13 15:08:41.996497994 +0100 +++ /var/tmp/diff_new_pack.uK3rm8/_new 2025-03-13 15:08:42.004498330 +0100 @@ -19,7 +19,7 @@ %define sname cli %define binname spicetify Name: spicetify-cli -Version: 2.39.3 +Version: 2.39.5 Release: 0 Summary: Command-line tool to customize Spotify client License: LGPL-2.1-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.uK3rm8/_old 2025-03-13 15:08:42.244508398 +0100 +++ /var/tmp/diff_new_pack.uK3rm8/_new 2025-03-13 15:08:42.264509236 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/spicetify/cli</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v2.39.3</param> + <param name="revision">v2.39.5</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.uK3rm8/_old 2025-03-13 15:08:42.420515780 +0100 +++ /var/tmp/diff_new_pack.uK3rm8/_new 2025-03-13 15:08:42.460517458 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/spicetify/cli</param> - <param name="changesrevision">0414d766239b51f1d6cff6802c9fb361e4a64fe4</param></service></servicedata> + <param name="changesrevision">c99cdf6673e1a81a64a426117538b19c042e4f3e</param></service></servicedata> (No newline at EOF) ++++++ cli-2.39.3.obscpio -> cli-2.39.5.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/CustomApps/lyrics-plus/index.js new/cli-2.39.5/CustomApps/lyrics-plus/index.js --- old/cli-2.39.3/CustomApps/lyrics-plus/index.js 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/CustomApps/lyrics-plus/index.js 2025-03-01 00:22:37.000000000 +0100 @@ -58,9 +58,14 @@ delay: 0, }, providers: { + lrclib: { + on: getConfig("lyrics-plus:provider:lrclib:on"), + desc: "Lyrics sourced from lrclib.net. Supports both synced and unsynced lyrics. LRCLIB is a free and open-source lyrics provider.", + modes: [SYNCED, UNSYNCED], + }, musixmatch: { on: getConfig("lyrics-plus:provider:musixmatch:on"), - desc: "Fully compatible with Spotify. Requires a token that can be retrieved from the official Musixmatch app. If you have problems with retrieving lyrics, try refreshing the token by clicking <code>Refresh Token</code> button.", + desc: "Fully compatible with Spotify. Requires a token that can be retrieved from the official Musixmatch app. If you have problems with retrieving lyrics, try refreshing the token by clicking <code>Refresh Token</code> button. You may need to be forced to use your own CORS Proxy to use this provider.", token: localStorage.getItem("lyrics-plus:provider:musixmatch:token") || "21051986b9886beabe1ce01c3ce94c96319411f8f2c122676365e3", modes: [KARAOKE, SYNCED, UNSYNCED], }, @@ -70,15 +75,10 @@ modes: [SYNCED, UNSYNCED], }, netease: { - on: getConfig("lyrics-plus:provider:netease:on"), + on: getConfig("lyrics-plus:provider:netease:on", false), desc: "Crowdsourced lyrics provider ran by Chinese developers and users.", modes: [KARAOKE, SYNCED, UNSYNCED], }, - lrclib: { - on: getConfig("lyrics-plus:provider:lrclib:on"), - desc: "Lyrics sourced from lrclib.net. Supports both synced and unsynced lyrics. LRCLIB is a free and open-source lyrics provider.", - modes: [SYNCED, UNSYNCED], - }, genius: { on: spotifyVersion >= "1.2.31" ? false : getConfig("lyrics-plus:provider:genius:on"), desc: "Provide unsynced lyrics with insights from artists themselves. Genius is disabled and cannot be used as a provider on <code>1.2.31</code> and higher.", @@ -175,9 +175,10 @@ this.styleVariables = {}; this.fullscreenContainer = document.createElement("div"); this.fullscreenContainer.id = "lyrics-fullscreen-container"; - this.mousetrap = new Spicetify.Mousetrap(); + this.mousetrap = null; this.containerRef = react.createRef(null); this.translator = null; + this.initMoustrap(); // Cache last state this.languageOverride = CONFIG.visual["translate:detect-language-override"]; this.translate = CONFIG.visual.translate; @@ -647,6 +648,11 @@ reader.readAsText(file[0]); event.target.value = ""; } + initMoustrap() { + if (!this.mousetrap && Spicetify.Mousetrap) { + this.mousetrap = new Spicetify.Mousetrap(); + } + } componentDidMount() { this.onQueueChange = async ({ data: queue }) => { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/CustomApps/lyrics-plus/style.css new/cli-2.39.5/CustomApps/lyrics-plus/style.css --- old/cli-2.39.3/CustomApps/lyrics-plus/style.css 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/CustomApps/lyrics-plus/style.css 2025-03-01 00:22:37.000000000 +0100 @@ -704,6 +704,9 @@ .split .lyrics-versionSelector select { width: 100%; } +.main-content-view { + height: 100%; +} @media (min-width: 1024px) { .split .lyrics-lyricsContainer-LyricsLine { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/Extensions/popupLyrics.js new/cli-2.39.5/Extensions/popupLyrics.js --- old/cli-2.39.3/Extensions/popupLyrics.js 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/Extensions/popupLyrics.js 2025-03-01 00:22:37.000000000 +0100 @@ -18,6 +18,7 @@ num = setInterval(() => postMessage("popup-lyric-update-ui"), 16.66); } else if (event.data === "popup-lyric-stop-update") { clearInterval(num); + postMessage("popup-lyric-update-ui"); num = null; } }; @@ -25,6 +26,8 @@ PopupLyrics(); } +let CACHE = {}; + function PopupLyrics() { const { Player, CosmosAsync, LocalStorage, ContextMenu } = Spicetify; @@ -40,6 +43,21 @@ } }; + let workerIsRunning = null; + document.addEventListener("visibilitychange", (e) => { + if (e.target.hidden) { + if (!workerIsRunning) { + worker.postMessage("popup-lyric-request-update"); + workerIsRunning = true; + } + } else { + if (workerIsRunning) { + worker.postMessage("popup-lyric-stop-update"); + workerIsRunning = false; + } + } + }); + const LyricUtils = { normalize(s, emptySymbol = true) { const result = s @@ -324,7 +342,7 @@ musixmatch: { on: boolLocalStorage("popup-lyrics:services:musixmatch:on"), call: LyricProviders.fetchMusixmatch, - desc: `Fully compatible with Spotify. Requires a token that can be retrieved from the official Musixmatch app. Follow instructions on <a href="https://spicetify.app/docs/faq#sometimes-popup-lyrics-andor-lyrics-plus-seem-to-not-work">Spicetify Docs</a>.`, + desc: "Fully compatible with Spotify. Requires a token that can be retrieved from the official Musixmatch app. If you have problems with retrieving lyrics, try refreshing the token by clicking <code>Refresh Token</code> button.", token: LocalStorage.get("popup-lyrics:services:musixmatch:token") || "2005218b74f939209bda92cb633c7380612e14cb7fe92dcd6a780f", }, spotify: { @@ -421,9 +439,11 @@ let sharedData = {}; - Player.addEventListener("songchange", updateTrack); + Player.addEventListener("songchange", () => { + updateTrack(); + }); - async function updateTrack() { + async function updateTrack(refresh = false) { if (!lyricVideoIsOpen) { return; } @@ -443,20 +463,25 @@ uri: Player.data.item.uri, }; - for (const name of userConfigs.servicesOrder) { - const service = userConfigs.services[name]; - if (!service.on) continue; - sharedData = { lyrics: [] }; + if (CACHE?.[info.uri]?.lyrics?.length && !refresh) { + sharedData = CACHE[info.uri]; + } else { + for (const name of userConfigs.servicesOrder) { + const service = userConfigs.services[name]; + if (!service.on) continue; + sharedData = { lyrics: [] }; + + try { + const data = await service.call(info); + sharedData = data; + CACHE[info.uri] = sharedData; - try { - const data = await service.call(info); - console.log(data); - sharedData = data; - if (!sharedData.error) { - return; + if (!sharedData.error) { + return; + } + } catch (err) { + sharedData = { error: "No lyrics" }; } - } catch (err) { - sharedData = { error: "No lyrics" }; } } } @@ -755,7 +780,6 @@ ctx.restore(); } - let workerIsRunning = null; let timeout = null; async function tick(options) { @@ -791,17 +815,7 @@ return; } - if (document.hidden) { - if (!workerIsRunning) { - worker.postMessage("popup-lyric-request-update"); - workerIsRunning = true; - } - } else { - if (workerIsRunning) { - worker.postMessage("popup-lyric-stop-update"); - workerIsRunning = false; - } - + if (!document.hidden) { requestAnimationFrame(() => tick(options)); } } @@ -815,11 +829,20 @@ function openConfig(event) { event.preventDefault(); - if (!configContainer) { + + // Reset on reopen + if (configContainer) { + resetTokenButton(configContainer); + } else { configContainer = document.createElement("div"); configContainer.id = "popup-config-container"; const style = document.createElement("style"); style.innerHTML = ` +.setting-row { + display: flex; + justify-content: space-between; + align-items: center; +} .setting-row::after { content: ""; display: table; @@ -831,13 +854,16 @@ align-items: center; } .setting-row .col.description { - float: left; padding-right: 15px; cursor: default; + width: 50%; } .setting-row .col.action { - float: right; - text-align: right; + justify-content: flex-end; + width: 50%; +} +.popup-config-col-margin { + margin-top: 10px; } button.switch { align-items: center; @@ -859,6 +885,27 @@ height: 22px; padding: 6px; } +button.btn { + font-weight: 700; + display: block; + background-color: rgba(var(--spice-rgb-shadow), .7); + border-radius: 500px; + transition-duration: 33ms; + transition-property: background-color, border-color, color, box-shadow, filter, transform; + padding-inline: 15px; + border: 1px solid #727272; + color: var(--spice-text); + min-block-size: 32px; + cursor: pointer; +} +button.btn:hover { + transform: scale(1.04); + border-color: var(--spice-text); +} +button.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} #popup-config-container select { color: var(--spice-text); background: rgba(var(--spice-rgb-shadow), .7); @@ -867,7 +914,6 @@ } #popup-config-container input { width: 100%; - margin-top: 10px; padding: 0 5px; height: 32px; border: 0; @@ -945,6 +991,13 @@ userConfigs.delay = Number(state); LocalStorage.set("popup-lyrics:delay", state); }); + const clearCache = descriptiveElement( + createButton("Clear Memory Cache", "Clear Memory Cache", () => { + CACHE = {}; + updateTrack(); + }), + "Loaded lyrics are cached in memory for faster reloading. Press this button to clear the cached lyrics from memory without restarting Spotify." + ); const serviceHeader = document.createElement("h2"); serviceHeader.innerText = "Services"; @@ -975,7 +1028,7 @@ const id = el.dataset.id; userConfigs.services[id].on = state; LocalStorage.set(`popup-lyrics:services:${id}:on`, state); - updateTrack(); + updateTrack(true); } function posCallback(el, dir) { @@ -990,23 +1043,28 @@ LocalStorage.set("popup-lyrics:services-order", JSON.stringify(userConfigs.servicesOrder)); stackServiceElements(); - updateTrack(); - } - - function tokenChangeCallback(el, inputEl) { - const newVal = inputEl.value; - const id = el.dataset.id; - userConfigs.services[id].token = newVal; - LocalStorage.set(`popup-lyrics:services:${id}:token`, newVal); - updateTrack(); + updateTrack(true); } for (const name of userConfigs.servicesOrder) { - userConfigs.services[name].element = createServiceOption(name, userConfigs.services[name], switchCallback, posCallback, tokenChangeCallback); + userConfigs.services[name].element = createServiceOption(name, userConfigs.services[name], switchCallback, posCallback); } stackServiceElements(); - configContainer.append(style, optionHeader, smooth, center, cover, blurSize, fontSize, ratio, delay, serviceHeader, serviceContainer); + configContainer.append( + style, + optionHeader, + smooth, + center, + cover, + blurSize, + fontSize, + ratio, + delay, + clearCache, + serviceHeader, + serviceContainer + ); } Spicetify.PopupModal.display({ title: "Popup Lyrics", @@ -1084,8 +1142,125 @@ return container; } + // if name is null, the element can be used without a description. + function createButton(name, defaultValue, callback) { + let container; + + if (name) { + container = document.createElement("div"); + container.innerHTML = ` + <div class="setting-row"> + <label class="col description">${name}</label> + <div class="col action"> + <button id="popup-lyrics-clickbutton" class="btn">${defaultValue}</button> + </div> + </div>`; + + const button = container.querySelector("#popup-lyrics-clickbutton"); + button.onclick = () => { + callback(); + }; + } else { + container = document.createElement("button"); + container.innerHTML = defaultValue; + container.className = "btn "; + + container.onclick = () => { + callback(); + }; + } + + return container; + } + // if name is null, the element can be used without a description. + function createTextfield(name, defaultValue, placeholder, callback) { + let container; + + if (name) { + container = document.createElement("div"); + container.className = "setting-column"; + container.innerHTML = ` + <label class="row-description">${name}</label> + <div class="popup-row-option action"> + <input id="popup-lyrics-textfield" placeholder="${placeholder}" value="${defaultValue}" /> + </div>`; + + const textfield = container.querySelector("#popup-lyrics-textfield"); + textfield.onchange = () => { + callback(); + }; + } else { + container = document.createElement("input"); + container.placeholder = placeholder; + container.value = defaultValue; + + container.onchange = (e) => { + callback(e.target.value); + }; + } + + return container; + } + function descriptiveElement(element, description) { + const desc = document.createElement("span"); + desc.innerHTML = description; + element.append(desc); + return element; + } + + function resetTokenButton(container) { + const button = container.querySelector("#popup-lyrics-refresh-token"); + if (button) { + button.innerHTML = "Refresh token"; + button.disabled = false; + } + } + + function musixmatchTokenElements(defaultVal, id) { + const button = createButton(null, "Refresh token", clickRefresh); + button.className += "popup-config-col-margin"; + button.id = "popup-lyrics-refresh-token"; + const textfield = createTextfield(null, defaultVal.token, `Place your ${id} token here`, changeTokenfield); + textfield.className += "popup-config-col-margin"; + + function clickRefresh() { + button.innerHTML = "Refreshing token..."; + button.disabled = true; + + Spicetify.CosmosAsync.get("https://apic-desktop.musixmatch.com/ws/1.1/token.get?app_id=web-desktop-app-v1.0", null, { + authority: "apic-desktop.musixmatch.com", + }) + .then(({ message: response }) => { + if (response.header.status_code === 200 && response.body.user_token) { + button.innerHTML = "Token refreshed"; + textfield.value = response.body.user_token; + textfield.dispatchEvent(new Event("change")); + } else if (response.header.status_code === 401) { + button.innerHTML = "Too many attempts"; + } else { + button.innerHTML = "Failed to refresh token"; + console.error("Failed to refresh token", response); + } + }) + .catch((error) => { + button.innerHTML = "Failed to refresh token"; + console.error("Failed to refresh token", error); + }); + } + + function changeTokenfield(value) { + userConfigs.services.musixmatch.token = value; + LocalStorage.set("popup-lyrics:services:musixmatch:token", value); + updateTrack(true); + } + + const container = document.createElement("div"); + container.append(button); + container.append(textfield); + return container; + } - function createServiceOption(id, defaultVal, switchCallback, posCallback, tokenCallback) { + function createServiceOption(id, defaultVal, switchCallback, posCallback) { const name = id.replace(/^./, (c) => c.toUpperCase()); const container = document.createElement("div"); @@ -1113,12 +1288,8 @@ </div> <span>${defaultVal.desc}</span>`; - if (defaultVal.token !== undefined) { - const input = document.createElement("input"); - input.placeholder = `Place your ${id} token here`; - input.value = defaultVal.token; - input.onchange = () => tokenCallback(container, input); - container.append(input); + if (id === "musixmatch") { + container.append(musixmatchTokenElements(defaultVal)); } const [up, down, slider] = container.querySelectorAll("button"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/css-map.json new/cli-2.39.5/css-map.json --- old/cli-2.39.3/css-map.json 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/css-map.json 2025-03-01 00:22:37.000000000 +0100 @@ -271,6 +271,7 @@ "X05XDhpQJ7THPHfgbUk1": "main-confirmDialog-buttonContainer", "RVgHI2ejYct8LjT1AO7m": "main-confirmDialog-container", "m0yIuS1Q6XRA5R4PNEhl": "main-confirmDialog-overlay", + "KL8t9WB65UfUEPuTFAhO": "main-content-view", "gQoa8JTSpjSmYyABcag2": "main-connectBar-connectBar", "T3hkVxXuSbCYOD2GIeQd": "main-connectBar-connected", "GcHojieewpdN1c8vbtwk": "main-connectBar-connecting", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/globals.d.ts new/cli-2.39.5/globals.d.ts --- old/cli-2.39.3/globals.d.ts 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/globals.d.ts 2025-03-01 00:22:37.000000000 +0100 @@ -540,6 +540,7 @@ * @param uri Any type of URI that has artwork (playlist, track, album, artist, show, ...) */ function colorExtractor(uri: string): Promise<{ + DARK_VIBRANT: string; DESATURATED: string; LIGHT_VIBRANT: string; PROMINENT: string; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/spicetify.go new/cli-2.39.5/spicetify.go --- old/cli-2.39.3/spicetify.go 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/spicetify.go 2025-03-01 00:22:37.000000000 +0100 @@ -17,6 +17,7 @@ "github.com/spicetify/cli/src/cmd" spotifystatus "github.com/spicetify/cli/src/status/spotify" "github.com/spicetify/cli/src/utils" + "github.com/spicetify/cli/src/utils/isAdmin" ) var ( @@ -24,14 +25,15 @@ ) var ( - flags = []string{} - commands = []string{} - quiet = false - extensionFocus = false - appFocus = false - styleFocus = false - noRestart = false - liveRefresh = false + flags = []string{} + commands = []string{} + quiet = false + extensionFocus = false + appFocus = false + styleFocus = false + noRestart = false + liveRefresh = false + bypassAdminCheck = false ) func init() { @@ -66,6 +68,8 @@ for _, v := range flags { switch v { + case "--bypass-admin": + bypassAdminCheck = true case "-c", "--config": fmt.Println(cmd.GetConfigPath()) os.Exit(0) @@ -110,6 +114,22 @@ os.Stdout = nil } + if isAdmin.Check(bypassAdminCheck) { + utils.PrintError("Spicetify should not be run with administrator/root privileges") + utils.PrintError("Running as admin can cause Spotify to show a black/blank window after applying spicetify") + utils.PrintError("This happens because Spotify (running as a normal user) can't access files modified with admin privileges") + utils.PrintInfo("If you understand the risks and need to continue anyway, you can use the '--bypass-admin' flag.") + utils.PrintInfo("Spicetify is now exiting...") + os.Exit(1) + } + + for i, flag := range flags { + if flag == "--bypass-admin" { + flags = append(flags[:i], flags[i+1:]...) + break + } + } + utils.MigrateConfigFolder() utils.MigrateFolders() cmd.InitConfig(quiet) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/src/preprocess/preprocess.go new/cli-2.39.5/src/preprocess/preprocess.go --- old/cli-2.39.3/src/preprocess/preprocess.go 2025-02-14 18:20:05.000000000 +0100 +++ new/cli-2.39.5/src/preprocess/preprocess.go 2025-03-01 00:22:37.000000000 +0100 @@ -142,7 +142,7 @@ } if fileName == "xpui.css" { content = content + ` - .main-gridContainer-fixedWidth{grid-template-columns: repeat(auto-fill, var(--column-width));width: calc((var(--column-count) - 1) * var(--grid-gap)) + var(--column-count) * var(--column-width));}.main-cardImage-imageWrapper{background-color: var(--card-color, #333);border-radius: 6px;-webkit-box-shadow: 0 8px 24px rgba(0, 0, 0, .5);box-shadow: 0 8px 24px rgba(0, 0, 0, .5);padding-bottom: 100%;position: relative;width:100%;}.main-cardImage-image,.main-card-imagePlaceholder{height: 100%;left: 0;position: absolute;top: 0;width: 100%} + .main-gridContainer-fixedWidth{grid-template-columns: repeat(auto-fill, var(--column-width));width: calc((var(--column-count) - 1) * var(--grid-gap)) + var(--column-count) * var(--column-width));}.main-cardImage-imageWrapper{background-color: var(--card-color, #333);border-radius: 6px;-webkit-box-shadow: 0 8px 24px rgba(0, 0, 0, .5);box-shadow: 0 8px 24px rgba(0, 0, 0, .5);padding-bottom: 100%;position: relative;width:100%;}.main-cardImage-image,.main-card-imagePlaceholder{height: 100%;left: 0;position: absolute;top: 0;width: 100%};.main-content-view{height:100%;} ` } return content diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/src/utils/isAdmin/unix.go new/cli-2.39.5/src/utils/isAdmin/unix.go --- old/cli-2.39.3/src/utils/isAdmin/unix.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cli-2.39.5/src/utils/isAdmin/unix.go 2025-03-01 00:22:37.000000000 +0100 @@ -0,0 +1,13 @@ +//go:build !windows +// +build !windows + +package isAdmin + +import "os" + +func Check(bypassAdminCheck bool) bool { + if bypassAdminCheck { + return false + } + return os.Geteuid() == 0 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cli-2.39.3/src/utils/isAdmin/windows.go new/cli-2.39.5/src/utils/isAdmin/windows.go --- old/cli-2.39.3/src/utils/isAdmin/windows.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cli-2.39.5/src/utils/isAdmin/windows.go 2025-03-01 00:22:37.000000000 +0100 @@ -0,0 +1,31 @@ +//go:build windows +// +build windows + +package isAdmin + +import ( + "golang.org/x/sys/windows" +) + +func Check(bypassAdminCheck bool) bool { + if bypassAdminCheck { + return false + } + + var sid *windows.SID + err := windows.AllocateAndInitializeSid( + &windows.SECURITY_NT_AUTHORITY, + 2, + windows.SECURITY_BUILTIN_DOMAIN_RID, + windows.DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &sid) + if err != nil { + return false + } + defer windows.FreeSid(sid) + + token := windows.Token(0) + member, err := token.IsMember(sid) + return err == nil && member +} ++++++ cli.obsinfo ++++++ --- /var/tmp/diff_new_pack.uK3rm8/_old 2025-03-13 15:08:43.340554371 +0100 +++ /var/tmp/diff_new_pack.uK3rm8/_new 2025-03-13 15:08:43.372555713 +0100 @@ -1,5 +1,5 @@ name: cli -version: 2.39.3 -mtime: 1739553605 -commit: 0414d766239b51f1d6cff6802c9fb361e4a64fe4 +version: 2.39.5 +mtime: 1740784957 +commit: c99cdf6673e1a81a64a426117538b19c042e4f3e ++++++ vendor.tar.gz ++++++