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:
parent
c4542ac668
commit
31bd9d918c
|
@ -133,6 +133,7 @@
|
|||
84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; };
|
||||
84FB9A301EDCD6C4003D53B9 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
84FF69B11FC3793300DC198E /* FaviconURLFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */; };
|
||||
D553738B20186C20006D8857 /* Article+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D553737C20186C1F006D8857 /* Article+Scriptability.swift */; };
|
||||
D5558FD32002245C0066386B /* ScriptingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5558FD22002245C0066386B /* ScriptingTests.swift */; };
|
||||
D5558FD5200225680066386B /* NSAppleEventDescriptor+UserRecordFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5558FD4200225680066386B /* NSAppleEventDescriptor+UserRecordFields.swift */; };
|
||||
D5558FD9200228D30066386B /* AppleEventUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5558FD7200228B80066386B /* AppleEventUtils.swift */; };
|
||||
|
@ -585,6 +586,7 @@
|
|||
84F2D5391FC2308B00998D64 /* UnreadFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadFeed.swift; sourceTree = "<group>"; };
|
||||
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Frameworks/Vendor/Sparkle.framework; sourceTree = SOURCE_ROOT; };
|
||||
84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconURLFinder.swift; sourceTree = "<group>"; };
|
||||
D553737C20186C1F006D8857 /* Article+Scriptability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Article+Scriptability.swift"; sourceTree = "<group>"; };
|
||||
D5558FD1200223F60066386B /* testGetURL.applescript */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.applescript; path = testGetURL.applescript; sourceTree = "<group>"; };
|
||||
D5558FD22002245C0066386B /* ScriptingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScriptingTests.swift; path = EvergreenTests/ScriptingTests/ScriptingTests.swift; sourceTree = SOURCE_ROOT; };
|
||||
D5558FD4200225680066386B /* NSAppleEventDescriptor+UserRecordFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "NSAppleEventDescriptor+UserRecordFields.swift"; path = "AppleEvents/NSAppleEventDescriptor+UserRecordFields.swift"; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -1186,6 +1188,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D5907D962004B7EB005947E5 /* Account+Scriptability.swift */,
|
||||
D553737C20186C1F006D8857 /* Article+Scriptability.swift */,
|
||||
D5A2678B20130ECF00A8D3C0 /* Author+Scriptability.swift */,
|
||||
D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */,
|
||||
D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */,
|
||||
|
@ -1261,12 +1264,12 @@
|
|||
TargetAttributes = {
|
||||
849C645F1ED37A5D003D8FC0 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = M8L2WTLA8W;
|
||||
ProvisioningStyle = Manual;
|
||||
DevelopmentTeam = 6V7D786XTL;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
849C64701ED37A5D003D8FC0 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
DevelopmentTeam = 6V7D786XTL;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = 849C645F1ED37A5D003D8FC0;
|
||||
};
|
||||
|
@ -1596,6 +1599,7 @@
|
|||
849A97641ED9EB96007D329B /* SidebarOutlineView.swift in Sources */,
|
||||
D5A2678C20130ECF00A8D3C0 /* Author+Scriptability.swift in Sources */,
|
||||
84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */,
|
||||
D553738B20186C20006D8857 /* Article+Scriptability.swift in Sources */,
|
||||
845EE7C11FC2488C00854A1F /* SmartFeed.swift in Sources */,
|
||||
84702AA41FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift in Sources */,
|
||||
D5907D7F2004AC00005947E5 /* NSApplication+Scriptability.swift in Sources */,
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
<element type="account">
|
||||
<cocoa key="accounts"/>
|
||||
</element>
|
||||
<element type="feed">
|
||||
<cocoa key="feeds"/>
|
||||
</element>
|
||||
</class>
|
||||
|
||||
<enumeration name="account type" code="enum">
|
||||
|
@ -89,6 +92,9 @@
|
|||
<element type="author">
|
||||
<cocoa key="authors"/>
|
||||
</element>
|
||||
<element type="article">
|
||||
<cocoa key="articles"/>
|
||||
</element>
|
||||
</class>
|
||||
|
||||
<class name="author" code="Athr" plural="authors" description="A feed author">
|
||||
|
@ -122,6 +128,52 @@
|
|||
</property>
|
||||
</class>
|
||||
|
||||
<class name="article" code="Arcl" plural="articles" description="An article in a feed">
|
||||
<cocoa class="ScriptableArticle"/>
|
||||
<property name="id" code="id " type="text" access="r" description="The unique id of the article as set by the feed">
|
||||
<cocoa key="uniqueId"/>
|
||||
</property>
|
||||
<property name="title" code="titl" type="text" access="r" description="The article title">
|
||||
<cocoa key="title"/>
|
||||
</property>
|
||||
<property name="url" code="URL " type="text" access="r" description="url for the article">
|
||||
<cocoa key="url"/>
|
||||
</property>
|
||||
<property name="contents" code="Cnts" type="text" access="r" description="text of the article">
|
||||
<cocoa key="contents"/>
|
||||
</property>
|
||||
<property name="html" code="HTML" type="text" access="r" description="html of the article">
|
||||
<cocoa key="html"/>
|
||||
</property>
|
||||
<property name="summary" code="Smry" type="text" access="r" description="a summary of the article">
|
||||
<cocoa key="summary"/>
|
||||
</property>
|
||||
<property name="published date" code="PDat" type="date" access="r" description="date the article was published">
|
||||
<cocoa key="datePublished"/>
|
||||
</property>
|
||||
<property name="arrived date" code="ADat" type="date" access="r" description="date the article was seen by Evergreen">
|
||||
<cocoa key="dateArrived"/>
|
||||
</property>
|
||||
<property name="modified date" code="MDat" type="date" access="r" description="date the article was last modified">
|
||||
<cocoa key="dateModified"/>
|
||||
</property>
|
||||
<property name="read" code="Read" type="boolean" access="r" description="has the article been read">
|
||||
<cocoa key="read"/>
|
||||
</property>
|
||||
<property name="starred" code="Star" type="boolean" access="r" description="has the article been marked with a star">
|
||||
<cocoa key="starred"/>
|
||||
</property>
|
||||
<property name="deleted" code="Delt" type="boolean" access="r" description="has the article been deleted by the user">
|
||||
<cocoa key="deleted"/>
|
||||
</property>
|
||||
<property name="image url" code="URL " type="text" access="r" description="an image url for the article">
|
||||
<cocoa key="imageURL"/>
|
||||
</property>
|
||||
<element type="author">
|
||||
<cocoa key="authors"/>
|
||||
</element>
|
||||
</class>
|
||||
|
||||
</suite>
|
||||
|
||||
<suite name="Internet Suite" code="GURL"
|
||||
|
|
|
@ -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 ?? ""
|
||||
}
|
||||
}
|
|
@ -91,4 +91,14 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
|
|||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ PROVISIONING_PROFILE_SPECIFIER =
|
|||
// /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig
|
||||
//
|
||||
|
||||
#include "../../SharedXcodeSettings/DeveloperSettings.xcconfig"
|
||||
#include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig"
|
||||
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
COMBINE_HIDPI_IMAGES = YES
|
||||
|
|
Loading…
Reference in New Issue