From b6c9eb890106ceebe7befee117da5557154834a5 Mon Sep 17 00:00:00 2001 From: Olof Hellman Date: Wed, 17 Jul 2019 00:37:54 -0700 Subject: [PATCH 1/5] Create Excel-CreateFeedStatisticsSpreadsheet.applescript Another sample script, this time targeting Excel and building a spreadsheet with simple statistics about feeds. --- ...reateFeedStatisticsSpreadsheet.applescript | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 AppleScript/Excel-CreateFeedStatisticsSpreadsheet.applescript diff --git a/AppleScript/Excel-CreateFeedStatisticsSpreadsheet.applescript b/AppleScript/Excel-CreateFeedStatisticsSpreadsheet.applescript new file mode 100644 index 000000000..b3fe5533a --- /dev/null +++ b/AppleScript/Excel-CreateFeedStatisticsSpreadsheet.applescript @@ -0,0 +1,49 @@ +-- This script creates an Excel spreadsheet with statistics about all the feeds in your NetNewsWire + +-- the exportToExcel() function creats a single line of data in a spreadsheet + +to exportToExcel(docname, rowIndex, feedname, numArticles, numStars, numRead) + tell application "Microsoft Excel" + tell worksheet 1 of document docname + set value of cell 1 of row rowIndex to feedname + set value of cell 2 of row rowIndex to numArticles + set value of cell 3 of row rowIndex to numStars + set value of cell 4 of row rowIndex to numRead + end tell + end tell +end exportToExcel + + +-- the script starts here +-- First, we make a new Excel spreadsheet and fill in the column headers + +tell application "Microsoft Excel" + set newdoc to make new document + tell worksheet 1 of newdoc + set value of cell 1 of row 1 to "Name of Feed" + set value of cell 2 of row 1 to "Articles" + set value of cell 3 of row 1 to "Read" + set value of cell 4 of row 1 to "Stars" + end tell + set docname to name of newdoc +end tell + +-- Then we loop though all the feeds of all the accounts +-- for each feed, we calculate how many articles there are, how many are read, and how many are starred +-- then, we send off the information to Excel + +set totalFeeds to 0 +tell application "NetNewsWire" + set allAccounts to every account + repeat with nthAccount in allAccounts + set allFeeds to every feed of nthAccount + repeat with nthFeed in allFeeds + set feedname to name of nthFeed + set articleCount to count (get every article of nthFeed) + set readCount to count (get every article of nthFeed where read is true) + set starCount to count (get every article of nthFeed where starred is true) + set totalFeeds to totalFeeds + 1 + my exportToExcel(docname, totalFeeds + 1, feedname, articleCount, readCount, starCount) + end repeat + end repeat +end tell From 48c5b67f57b5e3b7f251c684694660dd74e1121c Mon Sep 17 00:00:00 2001 From: Olof Hellman Date: Wed, 10 Jul 2019 23:52:01 -0700 Subject: [PATCH 2/5] Create OmniFocus-AddToNNWReadingList.applescript --- .../OmniFocus-AddToNNWReadingList.applescript | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 AppleScript/OmniFocus-AddToNNWReadingList.applescript diff --git a/AppleScript/OmniFocus-AddToNNWReadingList.applescript b/AppleScript/OmniFocus-AddToNNWReadingList.applescript new file mode 100644 index 000000000..310047578 --- /dev/null +++ b/AppleScript/OmniFocus-AddToNNWReadingList.applescript @@ -0,0 +1,42 @@ +-- This script presumes that you are an OmniFocus user, +-- and that you'd like to have a project in OmniFocus for a reading list of articles from NetNewsWire. +-- Running this script creates a new task in an OmniFocus project called "NetNewsWire reading list" +-- with information about the current article. + +-- Ideally, the name of the task will be the name of the article, but some articles don't have names +-- so if there is not name for the article, just use a default string "A NetNewsWireArticle without a title" +to getTitleOrSomething() + tell application "NetNewsWire" + set myTitle to the title of the current article + if (myTitle is "") then + set myTitle to "A NetNewsWireArticle without a title" + end if + end tell +end getTitleOrSomething + + +-- Here's where the script starts + +-- first get the url and the title of the current article +tell application "NetNewsWire" + set myUrl to the url of the current article + set myTitle to my getTitleOrSomething() +end tell + +tell application "OmniFocus" + tell document 1 + + -- Second, ensure that the front OmniFocus document has a project called "NetNewsWire reading list" + set names to name of every project + if names does not contain "NetNewsWire reading list" then + make new project with properties {name:"NetNewsWire reading list"} + end if + + -- lastly, add a task in that project referring to the current article + -- the "Note" field of the task will contain the url for the article + tell project "NetNewsWire reading list" + make new task with properties {name:myTitle, note:myUrl} + end tell + + end tell +end tell \ No newline at end of file From 4fc1998cf3d6ca58b276136f57935849693b2f07 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Wed, 17 Jul 2019 15:41:21 -0500 Subject: [PATCH 3/5] Make Account and AccountDelegate interfaces more consistent by requiring the container parameter on removeFeed. Resolves #802 --- Frameworks/Account/Account.swift | 2 +- Frameworks/Account/AccountDelegate.swift | 2 +- .../Account/Feedbin/FeedbinAccountDelegate.swift | 2 +- .../Account/LocalAccount/LocalAccountDelegate.swift | 4 ++-- Mac/Scriptability/Account+Scriptability.swift | 4 +++- Shared/Commands/DeleteCommand.swift | 11 ++++++++++- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 20347183b..cf29c7700 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -401,7 +401,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, return feed } - public func removeFeed(_ feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) { + public func removeFeed(_ feed: Feed, from container: Container, completion: @escaping (Result) -> Void) { delegate.removeFeed(for: self, with: feed, from: container, completion: completion) } diff --git a/Frameworks/Account/AccountDelegate.swift b/Frameworks/Account/AccountDelegate.swift index 6c9cef9e2..3764186a0 100644 --- a/Frameworks/Account/AccountDelegate.swift +++ b/Frameworks/Account/AccountDelegate.swift @@ -36,7 +36,7 @@ protocol AccountDelegate { func createFeed(for account: Account, url: String, name: String?, container: Container, completion: @escaping (Result) -> Void) func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result) -> Void) func addFeed(for account: Account, with: Feed, to container: Container, completion: @escaping (Result) -> Void) - func removeFeed(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) + func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result) -> Void) func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result) -> Void) func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result) -> Void) diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift index 8d28bc646..4286c04ed 100644 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift @@ -392,7 +392,7 @@ final class FeedbinAccountDelegate: AccountDelegate { } - func removeFeed(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) { + func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result) -> Void) { if feed.folderRelationship?.count ?? 0 > 1 { deleteTagging(for: account, with: feed, from: container, completion: completion) } else { diff --git a/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift b/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift index f54c12ad7..30d69a5d8 100644 --- a/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift @@ -139,8 +139,8 @@ final class LocalAccountDelegate: AccountDelegate { completion(.success(())) } - func removeFeed(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) { - container?.removeFeed(feed) + func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result) -> Void) { + container.removeFeed(feed) completion(.success(())) } diff --git a/Mac/Scriptability/Account+Scriptability.swift b/Mac/Scriptability/Account+Scriptability.swift index 80637f6be..a89e59522 100644 --- a/Mac/Scriptability/Account+Scriptability.swift +++ b/Mac/Scriptability/Account+Scriptability.swift @@ -58,8 +58,10 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta var container: Container? = nil if let scriptableFolder = scriptableFeed.container as? ScriptableFolder { container = scriptableFolder.folder + } else { + container = account } - account.removeFeed(scriptableFeed.feed, from: container) { result in + account.removeFeed(scriptableFeed.feed, from: container!) { result in } } } diff --git a/Shared/Commands/DeleteCommand.swift b/Shared/Commands/DeleteCommand.swift index cb7f6f3cc..972ffcc8c 100644 --- a/Shared/Commands/DeleteCommand.swift +++ b/Shared/Commands/DeleteCommand.swift @@ -153,19 +153,28 @@ private struct SidebarItemSpecifier { func delete(completion: @escaping () -> Void) { if let feed = feed { + + guard let container = path.resolveContainer() else { + completion() + return + } + BatchUpdate.shared.start() - account?.removeFeed(feed, from: path.resolveContainer()) { result in + account?.removeFeed(feed, from: container) { result in BatchUpdate.shared.end() completion() self.checkResult(result) } + } else if let folder = folder { + BatchUpdate.shared.start() account?.removeFolder(folder) { result in BatchUpdate.shared.end() completion() self.checkResult(result) } + } } From a35c9e21dadfd905bfe926a02c509e89d1e863f7 Mon Sep 17 00:00:00 2001 From: Olof Hellman Date: Thu, 18 Jul 2019 08:15:14 -0700 Subject: [PATCH 4/5] Create Safari-OpenAllStarredArticles.applescript --- .../Safari-OpenAllStarredArticles.applescript | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 AppleScript/Safari-OpenAllStarredArticles.applescript diff --git a/AppleScript/Safari-OpenAllStarredArticles.applescript b/AppleScript/Safari-OpenAllStarredArticles.applescript new file mode 100644 index 000000000..cad33bb4d --- /dev/null +++ b/AppleScript/Safari-OpenAllStarredArticles.applescript @@ -0,0 +1,49 @@ +-- This script creates a new Safari window with all the starred articles in a NetNewsWire instance, each in its own tab + +-- declare the safariWindow property here so we can use is throughout the whole script + +property safariWindow : missing value + +-- the openTabInSafari() function opens a new tab in the appropriate window + +to openTabInSafari(theUrl) + tell application "Safari" + -- test if this is the first call to openTabInSafari() + if (my safariWindow is missing value) then + -- first time through, make a new window with the given url in the only tab + set newdoc to make new document at front with properties {URL:theUrl} + -- because we created the doucument "at front", we know it is window 1 + set safariWindow to window 1 + else + -- after the first time, make a new tab in the wndow we created the first tim + tell safariWindow + make new tab with properties {URL:theUrl} + end tell + end if + end tell +end openTabInSafari + + +-- the script starts here +-- First, initialize safariWindow to be missing value, so that the first time through +-- openTabInSafari() we'll make a new window to hold all our articles + +set safariWindow to missing value + + +-- Then we loop though all the feeds of all the accounts +-- for each feed, we find all the starred articles +--for each one of those, open a new tab in Safari + +tell application "NetNewsWire" + set allAccounts to every account + repeat with nthAccount in allAccounts + set allFeeds to every feed of nthAccount + repeat with nthFeed in allFeeds + set starredArticles to (get every article of nthFeed where starred is true) + repeat with nthArticle in starredArticles + my openTabInSafari(url of nthArticle) + end repeat + end repeat + end repeat +end tell From dbfcab089de961a5069530244ac7dd0a415cfb79 Mon Sep 17 00:00:00 2001 From: Olof Hellman Date: Thu, 18 Jul 2019 08:19:04 -0700 Subject: [PATCH 5/5] merge sample AppleScript from master branch for mac-candidate --- .../Mail-CreateOutgoingMessage.applescript | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 AppleScript/Mail-CreateOutgoingMessage.applescript diff --git a/AppleScript/Mail-CreateOutgoingMessage.applescript b/AppleScript/Mail-CreateOutgoingMessage.applescript new file mode 100644 index 000000000..0bd50c6e4 --- /dev/null +++ b/AppleScript/Mail-CreateOutgoingMessage.applescript @@ -0,0 +1,85 @@ +-- This script grabs the current article in NetNewsWire and copies relevant information about it +-- to a new outgoing message in Mail +-- the intended use is that the user wants to send email about the current article, and +-- would fill in the recipient and then send the message + +-- sometimes, an article has contents, and sometimes it has html contents +-- this function getContentsOrHtml() gets the contents as text, despite the representation +-- first it checks to see if there are plain text contents +-- if not, it looks for html contents, and converts those to plain text using a shell script that invokes textutil +-- if it can't find either plain text or html, it returns "couldn't find article text" +to getContentsOrHtml() + tell application "NetNewsWire" + set textContents to the contents of the current article + if textContents is not "" then + return textContents + else + set htmlContents to html of the current article + if htmlContents is not "" then + set shellScript to " echo '" & htmlContents & "' | /usr/bin/textutil -stdin -stdout -format html -convert txt" + set pureText to do shell script shellScript + return pureText + end if + end if + end tell + return "couldn't find article text" +end getContentsOrHtml + + +-- given a list of author names, generate a happily formatted list like "Jean MacDonald and James Dempsey" +-- if the list is more than two names, use Oxford comma structure: "Brent Simmons, Jean MacDonald, and James Dempsey" + +to formatListOfNames(listOfNames) + set c to count listOfNames + if c is 1 then + set formattedList to item 1 of listOfNames + else if c is 2 then + set formattedList to item 1 of listOfNames & " and " & item 2 of listOfNames + else + set frontOfList to items 1 thru (c - 1) of listOfNames + set lastName to item c of listOfNames + set tid to AppleScript's text item delimiters + set AppleScript's text item delimiters to ", " + set t1 to frontOfList as text + set formattedList to t1 & ", and " & lastName + set AppleScript's text item delimiters to tid + end if + return formattedList +end formatListOfNames + + +-- sometimes, an article has an author, sometimes it has more than one, sometimes there's no author +-- this function getAuthorStub() returns a string like " from Jean MacDonald " that can be used in crafting a message +-- about the current article. If there are no authors, it just returns a single space. +to getAuthorStub(authorNames) + try + if ((count authorNames) is greater than 0) then + return " from " & formatListOfNames(authorNames) & " " + end if + end try + return " " +end getAuthorStub + + + +-- Here's where the script starts + +-- first, get some relevant info out for NetNewsWire +tell application "NetNewsWire" + set articleUrl to the url of the current article + set articleTitle to the title of the current article + set authorNames to name of authors of the current article +end tell + + +-- then, prepare the message subject and message contents +set messageSubject to "From NetNewsWire to you: " & articleTitle +set myIntro to "Here's something" & getAuthorStub(authorNames) & "that I was reading on NetNewsWire: " +set messageContents to myIntro & return & return & articleUrl & return & return & getContentsOrHtml() + + +-- lastly, make a new outgoing message in Mail with the given subject and contents +tell application "Mail" + set m1 to make new outgoing message with properties {subject:messageSubject} + set content of m1 to messageContents +end tell \ No newline at end of file