【问题标题】:Reading iMessages with AppleScript使用 AppleScript 阅读 iMessage
【发布时间】:2018-06-13 15:41:12
【问题描述】:

我正在尝试编写一个脚本,它将遍历消息应用程序中的所有聊天 - 我的目标是找到我尚未回复的所有消息并向我发送提醒。

但我被困在第一格 - 我可以看到我有多少条消息:

tell application "Messages" to log (count of chats)

但我什至无法从聊天中获得简单的属性;例如:

tell application "Messages" to set x to started of first chat

给出错误:无法开始聊天 1。”从聊天 1 开始的数字 -1728

任何想法我哪里出错了......?

【问题讨论】:

  • 决定放弃这个,直接用shell脚本去数据库。如果它对任何人有帮助,我认为这将完成这项工作:sqlite3 -line ~/Library/Messages/chat.db "SELECT m.ROWID, text, MAX(date) lastMessageDate, is_from_me, h.id FROM message m INNER JOIN handle h ON h.ROWID=m.handle_id GROUP BY h.ROWID"
  • 确实,AppleScript 目前对 Messages 的作用并不大。给定从您的 SQL 查询返回的数据,您希望具体如何处理它?您只是想要一个包含每个电话号码/iMessage 地址及其最后回复的列表,还是想要使用此列表完成一些操作?

标签: macos applescript imessage


【解决方案1】:

我使用您的 sqlite3 代码进行了一些小调整,然后创建了这个 AppleScript,它会生成一个提醒列表(在 Reminders 应用程序中)。唯一的缺点是发件人显示为电话号码或 iMessage 地址,并且不会使用您的地址簿“转换”为姓名。这可以通过对联系人的一些tell命令和对电话号码进行搜索来实现,但这超出了目前这一特定工作的范围。

    -- Run an SQL query on the messages database via shell script
    do shell script (["sqlite3 -line ~/Library/Messages/chat.db ", ¬
        "'SELECT MAX(date) lastMessageDate, h.id, text ", ¬
        "FROM message m INNER JOIN handle h ON h.ROWID=m.handle_id ", ¬
        "WHERE is_from_me = 0 GROUP BY h.ROWID' | egrep -io -e '\\w+ = .+'"] as text)
    
    set query_response to result
        --> lastMessageDate = %timestamp%
        --> id = %phone number or iMessage address%
        --> text = %message content%
        --> ...
    
    -- Groups all messages into a single item of an array
    -- Each occurence of  "lastMessageDate = " indicates 
    -- a new message and, hence, a new array item.
    set AppleScript's text item delimiters to "lastMessageDate = "
    set query_response to rest of text items of query_response
    
    -- Loop through the array organise each message
    repeat with message in query_response
        
        -- Split the array item up into its components
        set [receivedOn, sentFrom, textContent] ¬
            to [paragraph 1, ¬
            text 6 thru -1 of paragraph 2, ¬
            text 8 thru -1 of paragraph 3] of message
        
        -- Convert ReceivedOn to a value representing
        -- the number of days since 01/01/2001
        set receivedOn to receivedOn / (1.0E+9 * 86400)
        
        -- Convert ReceivedOn again to the date
        -- corresponding to the number of days since
        -- 01/01/2001, i.e. the date and time the message
        -- was sent
        set receivedOn to (date "Monday, 1 January 2001 at 00:00:00") + receivedOn * days
        
        -- Make a reminder
        tell application "Reminders"
            if not (exists (list named "Awaiting My Reply")) then ¬
                make new list with properties {name:"Awaiting My Reply"}
            
            tell list named "Awaiting My Reply"
                -- This creates a reminder with a past due date
                -- meaning you can sort the reminder list by due
                -- date to see who has been waiting longest
                -- for you to reply
                make new reminder with properties ¬
                    {name:"Reply To " & sentFrom, body:¬
                        textContent, due date:¬
                        receivedOn} ¬
                        
            end tell
        end tell
    end repeat

当然,如果您的任何短信碰巧包含短语“lastMessagedate =”,那么上面的脚本将无法正常工作。但是,有一些解决方法,我尝试了 sqlite3 返回的各种格式,包括 listcolumncsv,所有各有优缺点。

附录:从匹配的电话号码中检索联系人详细信息

经过大量实验,已成功将上述脚本与地址簿搜索集成,以将电话号码替换为联系人姓名:

    -- Replace dbID with your address book's serial number
    -- (look in ~/Library/Application Support/AddressBook/Sources)
    property dbID : "377FDA5C-013A-430A-A964-9943C0B40137"
    property db : {Messages:"/Users/CK/Library/Messages/chat.db", Addresses:"/Users/CK/Library/Application Support/AddressBook/Sources/" & dbID & "/AddressBook-v22.abcddb"}

    -- Run an SQL query on the messages database via shell script
    set Messages to do shell script (["sqlite3 -line ", ¬
        quoted form of (Messages in db) as text, ¬
        " 'SELECT MAX(date) lastMessageDate, h.id, text", ¬
        " FROM message m INNER JOIN handle h ON h.ROWID=m.handle_id", ¬
        " WHERE is_from_me = 0 GROUP BY h.ROWID'", ¬
        " | egrep -io -e '\\w+ = .+'"] as text)
    --> lastMessageDate = %timestamp%
    --> id = %phone number or iMessage address%
    --> text = %message content%
    --> ...
    
    set PhoneNumbers to do shell script (["sqlite3 -list -separator : ", ¬
        quoted form of (Addresses in db) as text, ¬
        " 'select r.ZFIRSTNAME, r.ZLASTNAME, p.ZFULLNUMBER", ¬
        " from ZABCDRECORD as r, ZABCDPHONENUMBER as p", ¬
        " WHERE p.ZOWNER=r.Z_PK'", ¬
        " | tr -c -d '[:alnum:]:[:cntrl:]:[:space:]:+#*'"] as text)
    --> %first name%:%last name:%phone number%
    --> ...
    
    set NamesAndNumbers to paragraphs of PhoneNumbers
    set AppleScript's text item delimiters to ":"
    tell NamesAndNumbers to ¬
        repeat with n from 1 to count it
            set its item n to ¬
                {firstname:text item 1, lastname:text item 2, phone:text item 3} ¬
                    of its item n
        end repeat
    
    -- Groups all messages into a single item of an array
    -- Each occurence of  "lastMessageDate = " indicates 
    -- a new message and, hence, a new array item.
    set AppleScript's text item delimiters to "lastMessageDate = "
    set Messages to rest of text items of Messages
    
    -- Loop through the array organise each message
    repeat with message in Messages
        
        -- Split the array item up into its components
        set [receivedOn, sentFrom, textContent] ¬
            to [paragraph 1, ¬
            text 6 thru -1 of paragraph 2, ¬
            text 8 thru -1 of paragraph 3] of message
        
        -- Convert ReceivedOn to a value representing
        -- the number of days since 01/01/2001
        set receivedOn to receivedOn / (1.0E+9 * 86400)
        
        -- Convert ReceivedOn again to the date
        -- corresponding to the number of days since
        -- 01/01/2001, i.e. the date and time the message
        -- was sent
        set receivedOn to (date "Monday, 1 January 2001 at 00:00:00") + receivedOn * days
        
        -- Keep the "+" delimiter but replace the "+44" with
        -- your own country's intl dialling code, e.g. {"+1", "+"}
        -- as this may or may not prefix a phone number
        set AppleScript's text item delimiters to {"+44", "+"}
        set sentFrom to last text item of sentFrom
        
        -- Find the name to whom the phone number belongs
        ignoring white space
            set match to ""
            repeat with person in NamesAndNumbers
                if the person's phone contains sentFrom then
                    set match to contents of the person
                    exit repeat
                end if
            end repeat
        end ignoring
        
        set AppleScript's text item delimiters to space
        if match is not "" then set sentFrom to the contents of ¬
            {firstname, lastname} of match as text
        
        -- Make a reminder
        tell application "Reminders"
            if not (exists (list named "Awaiting My Reply")) then ¬
                make new list with properties {name:"Awaiting My Reply"}
            
            tell list named "Awaiting My Reply"
                -- This creates a reminder with a past due date
                -- meaning you can sort the reminder list by due
                -- date to see who has been waiting longest
                -- for you to reply
                make new reminder with properties ¬
                    {name:"Reply To " & sentFrom, body:¬
                        textContent, due date:¬
                        receivedOn} ¬
                        
            end tell
        end tell
    end repeat

【讨论】:

  • 非常感谢 - 链接到联系人是下一个重大挑战 :)
  • 我认为像tell application "Contacts" to get name of every person whose value of phone 1 contains "%phone number%" 这样的东西可能会起作用,但它的匹配方式非常非常挑剔。如果我事先已经知道数字的格式等,我可以让它匹配个人。否则,我可以使用只有 3 位左右的非常广泛的数字匹配来获取人员列表。
  • 我使用了另一个 SQL 查询来访问联系人数据库并从那里检索电话号码。我必须找到我的相关联系人数据库的存储位置,并在~/Library/Application\ Support/AddressBook/Sources/%SERIALNUMBER%/AddressBook-v22.abcddb 找到它。用于检索姓名和电话号码的相关sqlite3 查询是select r.ZFIRSTNAME,r.ZLASTNAME,p.ZFULLNUMBER from ZABCDRECORD as r,ZABCDPHONENUMBER as p WHERE p.ZOWNER = r.Z_PK,我发现将其返回为-list 最有用。我将编写一个 AppleScript 以将其与上述集成并在我这样做时更新我的​​答案。
  • 完成了!在上面的答案中添加附录。
  • set receivedOn to (date "Monday, 1 January 2001 at 00:00:00") + receivedOn * days 出现错误:“2001 年 1 月 1 日星期一 00:00:00 的日期和时间日期无效。”
猜你喜欢
  • 2013-04-04
  • 2022-11-28
  • 1970-01-01
  • 2019-03-31
  • 2016-12-25
  • 1970-01-01
  • 2013-08-05
  • 2019-10-23
相关资源
最近更新 更多