在后台显示和更新 applescript 输出

Posted

技术标签:

【中文标题】在后台显示和更新 applescript 输出【英文标题】:Display and update applescript output in background 【发布时间】:2015-03-22 05:03:02 【问题描述】:

我有一个简短而可爱的程序,可以在 applescript 中输出我的内部和外部 ip。

这里是 Applescript 代码:

set inIP to IPv4 address of (get system info)
set exIP to (do shell script "curl ipecho.net/plain")
display dialog "Internal: " & inIP & "
External: " & exIP

我希望它在后台不断更新,最好不要像现在那样在显示对话框功能中更新。

我不希望 显示对话框 不断弹出,所以我正在寻找例如,在 菜单栏 中显示 IP。

我不知道这是否可能与 Applescript 相关

【问题讨论】:

我已在答案中更新了外部 IP 的代码,以使用 NSURL 请求而不是 curl。 【参考方案1】:

从 10.10(我认为)开始,您可以直接在脚本编辑器中使用 ApplescriptOBJC 创建真正的应用程序。

我之前没有真正尝试过,但是一旦你开始,它比我预期的要容易。

将此代码粘贴到新的脚本编辑器 Applescript 文档中。

使用另存为...菜单选项将其保存为保持打开的应用程序

然后将应用程序作为普通应用程序运行。

使用 OP 的原始 applescript 代码

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property StatusItem : missing value

-- check we are running in foreground - YOU MUST RUN AS APPLICATION. to be thread safe and not crash
if not (current application's NSThread's isMainThread()) as boolean then
    display alert "This script must be run from the main thread." buttons "Cancel" as critical
    error number -128
end if

-- create an NSStatusBar
on makeStatusBar()
    set bar to current application's NSStatusBar's systemStatusBar

    set StatusItem to bar's statusItemWithLength:-1.0

    -- set up the initial NSStatusBars title
    StatusItem's setTitle:"IP"
end makeStatusBar

-- update statusBar
on displayIP(theDisplay)
    StatusItem's setTitle:theDisplay
end displayIP

--repeat run  update code
on idle

    --get the IPs
    set inIP to IPv4 address of (get system info)
    set exIP to (do shell script "curl ipecho.net/plain")

    set theDisplay to "Internal: " & inIP & " External: " & exIP

    my displayIP(theDisplay)
    return 30 -- run every 30 seconds

end idle
-- call to create initial NSStatusBar
my makeStatusBar()

应用设置为每 30 秒运行一次。 它将使用您的 ips 更新菜单栏中的状态栏菜单。

我没有输入任何错误检查并将其留给您。

还请记住,如果您想在脚本编辑器中运行代码,请确保使用“运行应用程序”。


更新:1 我已将内部 IP 地址代码更改为使用 NShost,它比“get system info

更快且可能更可靠

更新:2

更新外部代码以使用 NSURL 请求而不是原始 Curl 执行 shell 脚本命令。

如果由于没有网络连接而导致获取外部 IP 地址失败...等,则可以更轻松地检查错误。

Curl 将返回有关失败原因的完整信息日志,恕我直言,这很痛苦。

更新的 AppleScript 代码

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property StatusItem : missing value

-- check we are running in foreground - YOU MUST RUN AS APPLICATION. to be thread safe and not crash
if not (current application's NSThread's isMainThread()) as boolean then
    display alert "This script must be run from the main thread." buttons "Cancel" as critical
    error number -128
end if

-- create an NSStatusBar
on makeStatusBar()
    set bar to current application's NSStatusBar's systemStatusBar

    set StatusItem to bar's statusItemWithLength:-1.0

    -- set up the initial NSStatusBars title
    StatusItem's setTitle:"IP"
end makeStatusBar

-- update statusBar
on displayIP(theDisplay)
    StatusItem's setTitle:theDisplay
end displayIP

--repeat run  update code
on idle

    --get the IPs

    set stringAddress to ""
    --use NSHost to get the Internal IP address 
    set inIPAddresses to current application's NSHost's currentHost's addresses

    --work through each item to find the IP
    repeat with i from 1 to number of items in inIPAddresses
        set anAddress to (current application's NSString's stringWithString:(item i of inIPAddresses))
        set ipCheck to (anAddress's componentsSeparatedByString:".")
        set the Counter to (count of ipCheck)

        if (anAddress as string) does not start with "127" then
            if Counter is equal to 4 then
                set stringAddress to anAddress
                -- found a match lets exit the repeat
                exit repeat
            end if
        else
            set stringAddress to "Not available"
        end if
    end repeat

    -- Get extenal IP

    set anError to missing value
    set iPURL to (current application's NSURL's URLWithString:"http://ipecho.net/plain")

    set NSUTF8StringEncoding to 4
    set exIP to (current application's NSString's stringWithContentsOfURL:iPURL encoding:NSUTF8StringEncoding |error|:anError) as string
    if exIP contains missing value then
        set exIP to "Not available"
    end if



    set theDisplay to "Intl: " & stringAddress & " Extnl: " & exIP

    --call to update statusBar
    my displayIP(theDisplay)

    return 30 -- run every 30 seconds

end idle
-- call to create initial NSStatusBar
my makeStatusBar()

更新 3

这将按照 OP 在 cmets 中的要求进行。

它现在有一个下拉菜单,其中包含外部或内部两个选项。

选择一个或另一个菜单项将更改状态栏以显示所选 IP。

最后一个很快就拼凑起来了,所以不太漂亮。 :-)

UPDATE 4它还会在退出应用程序和重新启动时保留选择。)


新代码:

  use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property StatusItem : missing value
property selectedMenu : "" -- each menu action will set this to a number, this will determin which IP is shown

property theDisplay : ""
property defaults : class "NSUserDefaults"

-- check we are running in foreground - YOU MUST RUN AS APPLICATION. to be thread safe and not crash
if not (current application's NSThread's isMainThread()) as boolean then
    display alert "This script must be run from the main thread." buttons "Cancel" as critical
    error number -128
end if

-- create an NSStatusBar
on makeStatusBar()
    set bar to current application's NSStatusBar's systemStatusBar

    set StatusItem to bar's statusItemWithLength:-1.0

    -- set up the initial NSStatusBars title
    StatusItem's setTitle:"IP"
    set newMenu to current application's NSMenu's alloc()'s initWithTitle:"Custom"
    set internalMenuItem to current application's NSMenuItem's alloc()'s initWithTitle:"Internal" action:"showInternal:" keyEquivalent:""
    set externalMenuItem to current application's NSMenuItem's alloc()'s initWithTitle:"External" action:"showIExternal:" keyEquivalent:""

    StatusItem's setMenu:newMenu
    newMenu's addItem:internalMenuItem
    newMenu's addItem:externalMenuItem
    internalMenuItem's setTarget:me
    externalMenuItem's setTarget:me
end makeStatusBar

--Show Internal ip Action
on showInternal:sender


    defaults's setObject:"1" forKey:"selectedMenu"
    my runTheCode()
end showInternal:

--Show External ip Action
on showIExternal:sender


    defaults's setObject:"2" forKey:"selectedMenu"
    my runTheCode()
end showIExternal:

-- update statusBar
on displayIP(theDisplay)
    StatusItem's setTitle:theDisplay
end displayIP

on runTheCode()

    set stringAddress to ""
    --use NSHost to get the Internal IP address 
    set inIPAddresses to current application's NSHost's currentHost's addresses

    --work through each item to find the IP
    repeat with i from 1 to number of items in inIPAddresses
        set anAddress to (current application's NSString's stringWithString:(item i of inIPAddresses))
        set ipCheck to (anAddress's componentsSeparatedByString:".")
        set the Counter to (count of ipCheck)

        if (anAddress as string) does not start with "127" then
            if Counter is equal to 4 then
                set stringAddress to anAddress
                -- found a match lets exit the repeat
                exit repeat
            end if
        else
            set stringAddress to "Not available"
        end if
    end repeat

    -- Get extenal IP

    set anError to missing value
    set iPURL to (current application's NSURL's URLWithString:"http://ipecho.net/plain")

    set NSUTF8StringEncoding to 4
    set exIP to (current application's NSString's stringWithContentsOfURL:iPURL encoding:NSUTF8StringEncoding |error|:anError) as string
    if exIP contains missing value then
        set exIP to "Not available"
    end if

    set selectedMenu to (defaults's stringForKey:"selectedMenu") as string
    if selectedMenu is "" or selectedMenu contains missing value then
        set selectedMenu to "1"
    end if

    if selectedMenu is "1" then
        set theDisplay to "Intl: " & stringAddress
    else if selectedMenu is "2" then
        set theDisplay to " Extnl: " & exIP
    end if

    --call to update statusBar
    my displayIP(theDisplay)


end runTheCode

--repeat run  update code
on idle

    my runTheCode()
    --my displayIP(theDisplay)

    return 30 -- run every 30 seconds

end idle
-- call to create initial NSStatusBar
set defaults to current application's NSUserDefaults's standardUserDefaults
my makeStatusBar()

【讨论】:

有没有办法让它成为一个下拉菜单,您可以在其中选择内部和外部?还是问的太多了?另外,感谢您的帮助! @PatrickCook 更新 4 使所选菜单在退出并重新启动应用程序后保持不变 最后的评论,有没有好的教程?还有许多其他程序我想为其制作菜单项。再次感谢! @PatrickCook 您应该阅读 Xcode 文档中的“NSStatusBar 类参考”。描述了您可以使用 NSStatusBar 做的所有事情以及为什么不应该大声笑 @PatrickCook 没有一个简单的答案。该代码使用 Applescript 和 Objective - C,但使用 ApplescriptObjc 脚本桥语法。了解一些 Objective c 会有所帮助,但您需要 Xcode 才能使用 Objective c。 ApplescriptObjc 的大多数教程都使用了使用 Xcode 或 Applescript Bundles 的示例。并且实施起来更复杂。我在上面所做的事情在我仅通过脚本编辑器实现它的方式上是新的和更简单的,我没有看到任何教程这样做,但编码与您在谷歌上找到的许多教程处于相同的上下文中。

以上是关于在后台显示和更新 applescript 输出的主要内容,如果未能解决你的问题,请参考以下文章

AppleScript 基础(一)基本语法和数据类型

AppleScript无法获得api响应的引用形式

无声推送通知有效负载

带有自定义图标的applescript显示对话框

在 OSX 更新到优胜美地后,Applescript 无法“告诉”Spotify 播放

蒙特雷更新后python中的applescript无法正常工作