Scripting support for articles and basic article properties

Also, added support for accessing feeds directly from the top level
container, essentially skipping account as a hierarchy level.

With this change, a script like

tell app “Evergreen”
   title of every article of feed "Six Colors" where read is true
end tell

produces the expected result.
This commit is contained in:
Olof Hellman
2018-01-24 00:06:34 -08:00
parent c4542ac668
commit 31bd9d918c
6 changed files with 197 additions and 4 deletions

View File

@@ -0,0 +1,111 @@
//
// Article+Scriptability.swift
// Evergreen
//
// Created by Olof Hellman on 1/23/18.
// Copyright © 2018 Olof Hellman. All rights reserved.
//
import Foundation
import Account
import Data
@objc(ScriptableArticle)
class ScriptableArticle: NSObject, UniqueIdScriptingObject {
let article:Article
let container:ScriptingObjectContainer
init (_ article:Article, container:ScriptingObjectContainer) {
self.article = article
self.container = container
}
@objc(objectSpecifier)
override var objectSpecifier: NSScriptObjectSpecifier? {
let scriptObjectSpecifier = self.container.makeFormUniqueIDScriptObjectSpecifier(forObject:self)
return (scriptObjectSpecifier)
}
// MARK: --- ScriptingObject protocol ---
var scriptingKey: String {
return "articles"
}
// MARK: --- UniqueIdScriptingObject protocol ---
// articles have id in the Evergreen database and id in the feed
// article.uniqueID here is the feed unique id
var scriptingUniqueId:Any {
return article.uniqueID
}
// MARK: --- Scriptable properties ---
@objc(url)
var url:String {
return article.url ?? ""
}
@objc(uniqueId)
var uniqueId:String {
return article.uniqueID
}
@objc(title)
var title:String {
return article.title ?? ""
}
@objc(contents)
var contents:String {
return article.contentText ?? ""
}
@objc(html)
var html:String {
return article.contentHTML ?? ""
}
@objc(summary)
var summary:String {
return article.summary ?? ""
}
@objc(datePublished)
var datePublished:Date? {
return article.datePublished
}
@objc(dateModified)
var dateModified:Date? {
return article.dateModified
}
@objc(dateArrived)
var dateArrived:Date {
return article.status.dateArrived
}
@objc(read)
var read:Bool {
return article.status.boolStatus(forKey:.read)
}
@objc(starred)
var starred:Bool {
return article.status.boolStatus(forKey:.starred)
}
@objc(deleted)
var deleted:Bool {
return article.status.boolStatus(forKey:.userDeleted)
}
@objc(imageURL)
var imageURL:String {
return article.imageURL ?? ""
}
}

View File

@@ -90,5 +90,15 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
let feedAuthors = feed.authors ?? []
return feedAuthors.map { ScriptableAuthor($0, container:self) } as NSArray
}
@objc(articles)
var articles:NSArray {
let feedArticles = feed.fetchArticles()
// the articles are a set, use the sorting algorithm from the viewer
let sortedArticles = feedArticles.sorted(by:{
return $0.logicalDatePublished > $1.logicalDatePublished
})
return sortedArticles.map { ScriptableArticle($0, container:self) } as NSArray
}
}

View File

@@ -8,6 +8,7 @@
import Cocoa
import Account
import Data
extension NSApplication : ScriptingObjectContainer {
@@ -25,6 +26,21 @@ extension NSApplication : ScriptingObjectContainer {
return accounts.map { ScriptableAccount($0) } as NSArray
}
/*
accessing feeds from the application object skips the 'account' containment hierarchy
this allows a script like 'articles of feed "The Shape of Everything"' as a shorthand
for 'articles of feed "The Shape of Everything" of account "On My Mac"'
*/
@objc(feeds)
func feeds() -> NSArray {
let accounts = AccountManager.shared.accounts
let emptyFeeds:[Feed] = []
let feeds = accounts.reduce(emptyFeeds) { (result, nthAccount) -> [Feed] in
let accountFeeds = nthAccount.children.flatMap { $0 as? Feed }
return result + accountFeeds
}
return feeds.map { ScriptableFeed($0, container:self) } as NSArray
}
}