9

如何在 Spotify 歌曲最小化时为其加注星标?

好的,所以 Windows 上的 Spotify 应用程序没有内置支持全局热键和非常基本的热键,即使应用程序窗口当前处于活动状态也是如此。令人沮丧的是,“主演”当前正在播放的歌曲没有键盘快捷键,即使窗口处于活动状态也是如此。

所以我有一个自动热键脚本,它为我提供了用于播放控制、音量和复制歌曲标题(包括 em dash 修复)的全局热键,但我在试图弄清楚如何为当前歌曲加注星标时遇到了困难。

更麻烦的是,我只希望 Autohotkey 脚本在这首歌还没有加星标的情况下加星标。如果它已经出演了,那就别管它了。

我希望所有这一切都发生在应用程序位于托盘中时,而无需打开窗口。


编辑:半工作解决方案

所以我想出了一个合理的解决方案,即使程序被最小化,它也会打开一个上下文菜单,并且做所有事情,包括不取消明星的歌曲。不幸的是,上下文菜单意味着它将在瞬间最小化游戏等全屏应用程序。取决于游戏可能会很痛苦,但这是我能做的最好的事情,没有花哨的 DLL 调用和其他东西。

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

;|---------------|
;|--[ SOURCES ]--|
;|---------------|
;Base Spotify Script from: http://www.autohotkey.com/board/topic/36239-spotify-global-hotkeys/
;Base Starring Script from: http://superuser.com/questions/324416/any-spotify-tweaks-with-keyboard-shortcut-to-star-tracks

;|------------------|
;|--[ SETTING UP ]--|
;|------------------|
DetectHiddenWindows, On ;Detect Spotify even if it's minimized
#IfWinExist ahk_class SpotifyMainWindow ;Only do the following if Spotify is running
spotify = ahk_class SpotifyMainWindow ;Set variable for Spotify Window Name

;|---------------|
;|--[ HOTKEYS ]--|
;|---------------|
; "CTRL + ALT + PAGEUP" for previous 
^!PGUP:: 
{
    ControlSend, ahk_parent, ^{Left}, %spotify% 
    return 
}

; "CTRL + ALT + PAGEDOWN" for next 
^!PGDN:: 
{ 
    ControlSend, ahk_parent, ^{Right}, %spotify% 
    return 
} 

; "CTRL + ALT + HOME" for pause
^!Home::
{ 
    ControlSend, ahk_parent, {Space}, %spotify% 
    return
} 

; "CTRL + ALT + END" for track-name
^!End:: 
{ 
    WinGetTitle, spotify_playing, %spotify% ;Get the title of Spotify which contains the track-name

    StringTrimLeft, trimmed_playing, spotify_playing, 10 ;Get rid of extra text and place into 'trimmed_playing'
    StringReplace, replaced_playing, trimmed_playing, –, -, All ;Replace en dash with normal dash and place into 'replaced_playing'

    clipboard = %replaced_playing% ;Copy the fixed text to clipboard
    return 
} 

; "CTRL + ALT + UP" for volume up
^!Up::
{ 
    ControlSend, ahk_parent, ^{Up}, %spotify% 
    return 
} 

; "CTRL + ALT + DOWN" for volume down
^!Down::
{ 
    ControlSend, ahk_parent, ^{Down}, %spotify% 
    return 
} 

; "CTRL + ALT + INSERT" for starring the current song
^!Insert::
{ 
    ;Store active window and mouse position.
    MouseGetPos, , , winID

    ;Right click near the song title in the "Now Playing" box.
    WinGetPos,  ,  ,  , spotifyHeight, %spotify%
    clickX := 100
    clickY := spotifyHeight-70 
    ControlClick, x%clickX% y%clickY% , %spotify%, , Right, , NA

    ;Get the contents of the context menu.
    WinWait, ahk_class #32768
    SendMessage, 0x1E1 ;MN_GETHMENU
    allContextMenuInfo := ErrorLevel

    ;The "Star" command is the 2nd menu item.
    ;If the song is Unstarred the text is Star, and vice versa. But sometimes some wierd characters are included.
    ;The only reliable way I found is to check if the first letter is S.
    menuText_StarUnstar := GetContextMenuItemText(allContextMenuInfo, 2)
    StringGetPos, positionOfS, menuText_StarUnstar, S

    ;If S is the first letter, star the song.
    notStarred := (%positionOfS% = 0)
    If notStarred 
    {
        ;Arrow down to the Star menu item and press enter.
        ControlSend, ahk_parent, {Down}{Down}{Enter}, %spotify% 
    } 
    Else 
    {
        ;Just close the context menu.
        ControlSend, ahk_parent, {Escape}, %spotify% 
    }

    ;Restore original window and mouse position.
    WinActivate ahk_id %winID%

    return
}

;|-----------------|
;|--[ FUNCTIONS ]--|
;|-----------------|

;Context menu helper function.
GetContextMenuItemText(hMenu, nPos)
{
    length := DllCall("GetMenuString"
            , "UInt", hMenu
            , "UInt", nPos
            , "UInt", 0 ; NULL
            , "Int", 0  ; Get length
            , "UInt", 0x0400)   ; MF_BYPOSITION
        VarSetCapacity(lpString, length + 1)
        length := DllCall("GetMenuString"
            , "UInt", hMenu
            , "UInt", nPos
            , "Str", lpString
            , "Int", length + 1
            , "UInt", 0x0400)
    return lpString
}

我修改了一些隐藏在互联网上的现有脚本。其来源可以在源代码的顶部找到,如果有人想尝试让它在不出现上下文菜单的情况下完全工作,它可能会有所帮助。


正常使用应用程序时如何给歌曲加星标?

在 Spotify 中似乎只有 2 条路线可以为歌曲加注星标。

  1. 右键单击左下角的专辑封面,然后使用星号上下文菜单选项。
  2. 右键单击播放列表中的歌曲并使用星号上下文菜单选项。

为了让事情变得尴尬,如果某些东西已经加星标,星标菜单选项将在完全相同的位置替换为取消星标菜单选项。当菜单打开时,它们也有相同的快捷键(t 键)。因此,您不能在不先进行某种检查的情况下进行盲目的菜单选择。

那么我们可以采取哪些可能的路线呢?

右击左下角的专辑封面是唯一现实的路线。

如果我们可以在最小化的情况下从上下文菜单中读取文本,我们可以通过将文本从“星号”更改为“取消星号”来判断某些内容是否已加星标。在那次测试之后,我们可以决定是否按下 T 键来真正为这首歌加注星标。

我还花了一些时间在 Window Detective 上,看看我是否可以发送一个相对简单的 PostMessage/SendMessage 来为歌曲加注星标。但是我的经验很少,我不知道如何将它们链接在一起以获得我想要的结果。

我发现星号和取消星号上下文菜单选项实际上是不同的:

Star   -> WM_MENUSELECT (0x11F) | item identifier = 11 | flags = NONE | MF_HILITE
Unstar -> WM_MENUSELECT (0x11F) | item identifier = 12 | flags = NONE | MF_HILITE

但是我不知道如何真正将 PostMessages/SendMessages 链接在一起以打开菜单,然后只选择项目 #11,然后按 Enter。

Spotify 在为某事加注星标时收到的消息列表

以防万一这有助于确定是否可以执行 PostMessage/SendMessage 路由。

->WM_RBUTTONDOWN (0x204)
->WM_RBUTTONUP (0x205)
->WM_MENUSELECT (0x11F)
<-WM_MENUSELECT (0x11F)
->WM_KEYDOWN (0x100)
->WM_MENUSELECT (0x11F)
<-WM_MENUSELECT (0x11F)
->WM_KEYUP (0x101)

后记

我已经搜索了一段时间,试图找到 PostMessages/SendMessages 用于执行这种上下文菜单选择的好例子,但没有找到任何东西。

谢谢你的时间。

当前的自动热键脚本

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; "CTRL + ALT + PAGEUP"  for previous 
^!PGUP:: 
{
    DetectHiddenWindows, On 
    ControlSend, ahk_parent, ^{Left}, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 
    return 
}

; "CTRL + ALT + PAGEDOWN"  for next 
^!PGDN:: 
{ 
    DetectHiddenWindows, On 
    ControlSend, ahk_parent, ^{Right}, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 
    return 
} 

; "CTRL + ALT + HOME"  for pause
^!Home::
{ 
    DetectHiddenWindows, On 
    ControlSend, ahk_parent, {space}, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 
    return
} 

; "CTRL + ALT + END"  for info 
^!End:: 
{ 
    DetectHiddenWindows, On 
    WinGetTitle, spotify_playing, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 

    StringTrimLeft, trimmed_playing, spotify_playing, 10 
    StringReplace, replaced_playing, trimmed_playing, –, -, All

    clipboard = %replaced_playing%
    return 
} 

; "CTRL + ALT + UP"  for volume up
^!Up::
{ 
    DetectHiddenWindows, On 
    ControlSend, ahk_parent, ^{Up}, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 
    return 
} 

; "CTRL + ALT + DOWN"  for volume down
^!Down::
{ 
    DetectHiddenWindows, On 
    ControlSend, ahk_parent, ^{Down}, ahk_class SpotifyMainWindow 
    DetectHiddenWindows, Off 
    return 
} 

/*
PLAN: I want to make this star the current song if it's unstarred
NOTES: 
    WM_MENUSELECT for star seems to be item identifier 11, unstar is 12
    Star   -> WM_MENUSELECT (0x11F) | item identifier = 11 | flags = NONE | MF_HILITE
    Unstar -> WM_MENUSELECT (0x11F) | item identifier = 12 | flags = NONE | MF_HILITE
*/
; "CTRL + ALT + INSERT"  for starring the current song
^!Insert::
{ 
    DetectHiddenWindows, On 

    DetectHiddenWindows, Off 
    return 
}
4

2 回答 2

4

我目前在玩游戏时使用的非常简单:

MouseGetPos, x, y, origwin
WinActivate, ahk_class SpotifyMainWindow
click 183, 1000 ;
WinActivate, ahk_id %origwin%
MouseMove, %x%, %y%

完美替代您的其他代码;Spotify 响应媒体按钮,因此这些按钮很有效:

^!Left::Media_Prev
^!Right::Media_Next
^!Up::Volume_Up
^!Down::Volume_Down
^!Space::Media_Play_Pause

编辑:Spotify 改变了他们的布局。+ 随歌曲标题的长度移动。为了使其工作更加一致,我将功能更改为右键单击并“保存到您的音乐”。

FavouriteSpotifySong()
{
    WinGetPos, , , SPOTIFY_X_AXIS, SPOTIFY_Y_AXIS, ahk_class SpotifyMainWindow
    yPos := SPOTIFY_Y_AXIS - 30
    ControlClick, X25 Y%yPos%, ahk_class SpotifyMainWindow,, RIGHT
    Sleep 75
    yPos -= 54
    ControlClick, X33 Y%yPos%, ahk_class SpotifyMainWindow
}
于 2016-10-26T22:19:27.497 回答
0
SpotifyLove(flag)
{            
WinGetActiveTitle, CurOpen
MouseGetPos, MouseX, MouseY

IfWinExist ahk_exe Spotify.exe ; check if spotify is open
    winactivate ahk_exe Spotify.exe
else
    return
WinWait ahk_exe Spotify.exe

Click, 65 940 0; Spotify has a 60x60 pixel window with the menu in the top left corner. I have not find another way to activate the the main window except for this click. Any other solutions to are much appreciated.

WinGetPos, X, Y, W, H, A ; get the dimensions of the spotify window

; start searching for image in a rectangle. The first point of the rectangle X1,Y1 is 100 pixels above the bottom left corner. The other point of the rectangle X2,Y2 is 600 pixels right of the left edge and along the bottom of the window.

X1 := 0
X2 := 600
Y1 := H - 100
Y2 := H

; imagesearch is really crappy. *70 gives the function some leeway to find the right image in the window. We are searching for the heart. 

ImageSearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, *70 Z:\Pictures\heart.jpg

; click on heart if we like the song, click on the dislike button and "i dont like this song" otherwise.

A := OutputVarX+15
B := OutputVarY+15
if (flag == 1)
{
    Click, %A% %B%
} 
else {
    HateX := OutputVarX+50
    DontLikeSongX := HateX+10
    DontLikeSongY := OutputVarY-10
    Click, %HateX%, %OutputVarY%
    Sleep, 200
    Click, %DontLikeSongX%, %DontLikeSongY%
}

; return to previous window with the same mouse position.
WinRestore, %CurOpen%
WinMaximize, %CurOpen%
WinActivate, %CurOpen%
MouseMove, %MouseX%, %MouseY% 
}

^+S::
SpotifyLove(1)
Return

;^+d::
;SpotifyLove(0)
;Return

我很久以前在 AutoHotKey 的论坛上发现了这个,最近又回到了 AutoHotkey,不得不重新调整并花了一个小时才把它弄好。它仍然不完美,因为它使用的是 ImageSearch。确保从 spotify 应用程序中获取一个空心的片段,并提及它的 JPG 路径(在空心屏幕截图图像周围尽可能少地使用边框)并提及它的路径。它在大约 95% 的情况下都正确,但也不会消除在短时间内打开 spotify 应用程序的问题,因此在游戏期间不太有用。我评论了不喜欢这首歌的部分,因为它根本不起作用。

我设置的快捷方式是:“Ctrl + Shift + S”

编辑:从 Spotify Windows 应用程序添加 empty_heart 的链接。(https://imgur.com/a/eDWL1Zl

请记住,由于 Spotify 中不同标题长度的心脏位置不断变化,因此准确度仅为 95% 左右。

发布此内容时 Spotify 的当前 UI,也应该在上面的 imgur 链接中可见。

于 2021-07-12T12:53:39.677 回答