### Access Article Metadata and Content in Swift Source: https://context7.com/ranchero-software/netnewswire/llms.txt Provides examples for accessing article content, links, author information, and status tracking, as well as filtering sets of articles. ```swift import Articles let article: Article = // ... fetched from account print("Title: \(article.title ?? "Untitled")") print("Read: \(article.status.read)") print("Starred: \(article.status.starred)") let articles: Set
= // ... fetched articles let unreadOnly = articles.unreadArticles() ``` -------------------------------- ### Swift Downloader - HTTP Download Utility with Caching Source: https://context7.com/ranchero-software/netnewswire/llms.txt Provides a utility class for performing HTTP downloads with automatic caching for GET requests. It supports both asynchronous and callback-based downloads, and allows for custom URL requests. ```swift import RSWeb // Access shared downloader let downloader = Downloader.shared // Simple async download let url = URL(string: "https://example.com/image.png")! let (data, response) = try await downloader.download(url) if let data = data, let response = response as? HTTPURLResponse { print("Downloaded \(data.count) bytes") print("Status: \(response.statusCode)") print("Content-Type: \(response.mimeType ?? "Unknown")") } // Callback-based download downloader.download(url) { data, response, error in if let error = error { print("Download failed: \(error)") return } if let data = data { print("Downloaded \(data.count) bytes") // Process data... } } // Download with custom URLRequest var request = URLRequest(url: url) request.httpMethod = "GET" request.addValue("application/json", forHTTPHeaderField: "Accept") downloader.download(request) { data, response, error in // Handle response... } // Note: GET requests are automatically cached for a short time // Subsequent requests for the same URL may return cached data ``` -------------------------------- ### Initialize Ad Queue and Handle Lightbox Ads (JavaScript) Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/coco.html This snippet initializes a global ad queue and sets up event listeners for ad loading, specifically for a welcome lightbox. It checks for an ad-blocking cookie and displays the lightbox with appropriate formatting upon ad load. Dependencies include jQuery and a custom Atlantic.WelcomeScreen object. ```javascript window.ad_queue = window.ad_queue || []; window.ad_queue.push(function(){ // Be nice to those who whitelist if (Atlantic.Utils.readCookie("recently_adblocking")) { $(".welcome-lightbox").remove(); } $(".welcome-lightbox gpt-ad").on("ad-loaded", function(){ var $lightbox = $('#lightbox-welcome'); // The lightbox's class includes the size, so ipad // ads and other weird cases can have their own styling. $lightbox.addClass("active format-" + this.size.join("x")); if (typeof window.welcomeScreen === 'undefined') { window.welcomeScreen = new Atlantic.WelcomeScreen(); } window.welcomeScreen.show(); }); }); ``` -------------------------------- ### Get TV Show Details Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSCore/Tests/RSCoreTests/Resources/apple.html Retrieves detailed information about a specific TV show on Apple TV+, including metadata, images, and release dates. ```APIDOC ## GET /api/tv/show/{id} ### Description Retrieves detailed information about a specific TV show on Apple TV+. ### Method GET ### Endpoint /api/tv/show/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier for the TV show. ### Response #### Success Response (200) - **title** (string) - The title of the TV show. - **localizedType** (string) - The localized type of the content (e.g., "TV Show"). - **type** (string) - The general type of the content (e.g., "Show"). - **url** (string) - The URL to the TV show on Apple TV+. - **releaseDate** (integer) - The release date of the TV show as a Unix timestamp. - **isAppleOriginal** (boolean) - Indicates if the show is an Apple Original. - **extendedMetadata** (object) - Contains extended metadata like images and notes. - **images** (object) - Various image assets for the show. - **posterArt** (object) - Poster art details. - **channelSplashWide** (object) - Wide channel splash image. - **channelSplashTall** (object) - Tall channel splash image. - **singleColorContentLogo** (object) - Single color logo. - **longNote** (string) - A longer description of the show. - **shortNote** (string) - A shorter description of the show. - **genres** (array) - An array of genre objects. - **id** (string) - The genre ID. - **name** (string) - The genre name. - **type** (string) - The type of genre. - **url** (string) - The URL for the genre. - **images** (object) - General image assets for the show. - **shelfImage** (object) - Image for display on shelves. - **shelfImageBackground** (object) - Background image for shelves. - **transitionImage** (object) - Transition image. #### Response Example ```json { "title": "Ted Lasso", "localizedType": "TV Show", "type": "Show", "url": "https://tv.apple.com/us/show/ted-lasso/umc.cmc.vtoh0mn0xn7t3c643xqonfzy?l=en-US", "releaseDate": 1597363200000, "isAppleOriginal": true, "extendedMetadata": { "images": { "posterArt": { "width": 3840, "height": 2160, "url": "https://is1-ssl.mzstatic.com/image/thumb/ageP1PYyLi7UlNiWMva32Q/{w}x{h}.{f}", "supportsLayeredImage": true, "joeColor": "b:rgb(2,30,84) p:rgb(121,193,225) s:rgb(14,139,235) t:rgb(97,160,197) q:rgb(11,117,204)" }, "channelSplashWide": { "width": 4320, "height": 1800, "url": "https://is1-ssl.mzstatic.com/image/thumb/Features126/v4/28/39/2c/28392c38-d54d-4e4e-49fb-c9e4f434f2a6/42161e50-1a82-40ec-8d8a-cc7eba86d61f.png/{w}x{h}sr.{f}", "joeColor": "b:rgb(2,22,62) p:rgb(169,184,209) s:rgb(85,171,228) t:rgb(136,152,179) q:rgb(68,142,194)", "isP3": true }, "channelSplashTall": { "width": 1680, "height": 3636, "url": "https://is1-ssl.mzstatic.com/image/thumb/Features126/v4/b3/fa/77/b3fa7718-b692-ca56-87ce-5af818a447f7/955d54ab-6986-4e68-981d-b11df46a0029.png/{w}x{h}tc.{f}", "joeColor": "b:rgb(1,28,81) p:rgb(109,167,226) s:rgb(91,165,235) t:rgb(88,139,197) q:rgb(73,138,204)", "isP3": true }, "singleColorContentLogo": { "width": 5937, "height": 892, "url": "https://is1-ssl.mzstatic.com/image/thumb/Cc6MMzxFzD1gVqnd6IslKA/{w}x{h}.{f}", "joeColor": "b:rgb(255,255,255) p:rgb(12,12,12) s:rgb(25,25,25) t:rgb(61,61,61) q:rgb(71,71,71)" } }, "longNote": "Kindness makes a comeback.", "shortNote": "The heartwarming, hilarious hit about an American coach leading a UK soccer team." }, "genres": [ { "id": "umc.gnr.tv.comedy", "name": "Comedy", "type": "Genre", "url": "https://tv.apple.com/us/genre/comedy/umc.gnr.tv.comedy" } ], "id": "umc.cmc.vtoh0mn0xn7t3c643xqonfzy", "images": { "shelfImage": { "width": 3840, "height": 2160, "url": "https://is1-ssl.mzstatic.com/image/thumb/ageP1PYyLi7UlNiWMva32Q/{w}x{h}.{f}", "supportsLayeredImage": true, "joeColor": "b:rgb(2,30,84) p:rgb(121,193,225) s:rgb(14,139,235) t:rgb(97,160,197) q:rgb(11,117,204)" }, "shelfImageBackground": { "width": 3840, "height": 2160, "url": "https://is1-ssl.mzstatic.com/image/thumb/ihJBSuOxRtRXE6aDXdA7dw/{w}x{h}.{f}", "supportsLayeredImage": false, "joeColor": "b:rgb(1,27,78) p:rgb(100,194,225) s:rgb(75,148,224) t:rgb(81,161,196) q:rgb(60,124,195)" }, "transitionImage": { "width": 4320, "height": 3240, "url": "https://is1-ssl.mzstatic.com/image/thumb/8tZXIVmGubplrBRmZfc_fw/{w}x{h}sr.{f}", "isUber": true, "isP3": false, "joeColor": "b:rgb(2,5,41) p:rgb(165,200,235) s:rgb(108,156,216) t:rgb(132,161,196) q:rgb(87,126,181)", "supportsLayeredImage": false } } } ``` } ] } ] } ``` -------------------------------- ### YouTube Configuration Initialization Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html Sets up the global ytplayer object and applies configuration flags for experiment tracking and feature toggles. ```javascript (function() { window.ytplayer = {}; ytcfg.set({ "CLIENT_CANARY_STATE": "none", "DEVICE": "cbrand=robot&ceng=USER_DEFINED&cmodel=bot+or+crawler&cplatform=DESKTOP", "EXPERIMENT_FLAGS": { "kevlar_miniplayer": true, "enable_memberships_and_purchases": true } }); })(); ``` -------------------------------- ### Example Crash Log Format Source: https://github.com/ranchero-software/netnewswire/blob/main/Technotes/privacypolicy.markdown This snippet represents the structure of a crash log generated by NetNewsWire for Mac. It is used by developers to diagnose and fix application crashes. ```text Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 libsystem_secinit.dylib 0x00007fff6c06689f _libsecinit_setup_secinitd_client + 1393 1 libsystem_secinit.dylib 0x00007fff6c0662cd _libsecinit_initialize_once + 13 2 libdispatch.dylib 0x00007fff6be17dcf _dispatch_client_callout + 8 3 libdispatch.dylib 0x00007fff6be19515 _dispatch_once_callout + 20 4 libsystem_secinit.dylib 0x00007fff6c0662be _libsecinit_initializer + 79 5 libSystem.B.dylib 0x00007fff692639d4 libSystem_initializer + 136 ``` -------------------------------- ### POST /youtubei/v1/playlist/create Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html Creates a new playlist or adds a video to a new queue. ```APIDOC ## POST /youtubei/v1/playlist/create ### Description This endpoint is used to initialize a new playlist or queue containing specific video IDs. ### Method POST ### Endpoint /youtubei/v1/playlist/create ### Request Body - **videoIds** (array) - Required - A list of video IDs to include in the new playlist. - **params** (string) - Optional - Additional configuration parameters for playlist creation. ### Request Example { "videoIds": ["4DNogWaJqQY"], "params": "CAQ%3D" } ``` -------------------------------- ### Manage Feed Subscriptions in Swift Source: https://context7.com/ranchero-software/netnewswire/llms.txt Demonstrates how to access feed metadata, customize display settings, enable notifications, and manage conditional GET information for efficient polling. ```swift import Account let feed: Feed = // ... obtained from account print("Feed URL: \(feed.url)") print("Feed ID: \(feed.feedID)") print("Display Name: \(feed.nameForDisplay)") feed.editedName = "My Custom Feed Name" feed.newArticleNotificationsEnabled = true feed.readerViewAlwaysEnabled = true try await feed.account?.renameFeed(feed, name: "New Feed Name") ``` -------------------------------- ### POST /youtubei/v1/playlist/create Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html Creates a new playlist and adds a specified video to it. ```APIDOC ## POST /youtubei/v1/playlist/create ### Description Creates a new playlist for the authenticated user and adds the provided video ID to the new list. ### Method POST ### Endpoint /youtubei/v1/playlist/create ### Request Body - **videoIds** (array) - Required - List of video IDs to add to the new playlist. - **params** (string) - Required - Encoded parameters for playlist creation. ### Request Example { "videoIds": ["6ycdXvBhJgw"], "params": "CAQ%3D" } ### Response #### Success Response (200) - **status** (string) - Confirmation of playlist creation. #### Response Example { "status": "success" } ``` -------------------------------- ### Organize Feeds into Folders in Swift Source: https://context7.com/ranchero-software/netnewswire/llms.txt Shows how to create, rename, and delete folders, as well as how to add or remove feeds from the folder hierarchy and retrieve aggregate unread counts. ```swift import Account let account = AccountManager.shared.defaultAccount let techFolder = try await account.addFolder("Technology") techFolder.addFeedToTreeAtTopLevel(feed) techFolder.removeFeedFromTreeAtTopLevel(feed) try await account.renameFolder(techFolder, to: "Tech News") account.removeFolder(techFolder) { result in if case .success = result { print("Folder deleted") } } ``` -------------------------------- ### Symbolicate JSON Crash Logs (Bash) Source: https://github.com/ranchero-software/netnewswire/blob/main/scripts/README_SYMBOLICATION.md A script to handle and symbolicate newer JSON-format crash logs introduced in macOS 15+. It parses the JSON structure, extracts thread backtraces, and reformats the output into a readable text format. This script requires the `jq` utility to be installed. ```bash # JSON format crash logs (macOS 15+) ./symbolicate_json_crash.sh crash.log # Auto-find archive by UUID ./symbolicate_json_crash.sh crash.log # Specify archive path manually ./symbolicate_json_crash.sh crash.log ~/Library/Developer/Xcode/Archives/2024-11-28/MyApp.xcarchive ``` -------------------------------- ### Define Keyboard Shortcut Configuration Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html This JSON structure defines the keyboard shortcuts available for media playback, including keys for play/pause, seeking, and navigation. It maps specific keys to their corresponding playback actions. ```json { "hotkeyDialog": { "hotkeyDialogRenderer": { "title": { "runs": [{ "text": "Keyboard shortcuts" }] }, "sections": [{ "hotkeyDialogSectionRenderer": { "title": { "runs": [{ "text": "Playback" }] }, "options": [ { "hotkeyDialogSectionOptionRenderer": { "label": { "runs": [{ "text": "Toggle play/pause" }] }, "hotkey": "k" } }, { "hotkeyDialogSectionOptionRenderer": { "label": { "runs": [{ "text": "Rewind 10 seconds" }] }, "hotkey": "j" } }, { "hotkeyDialogSectionOptionRenderer": { "label": { "runs": [{ "text": "Fast forward 10 seconds" }] }, "hotkey": "l" } } ] } }] } } } ``` -------------------------------- ### Account: Manage Feeds and Folders in NetNewsWire (Swift) Source: https://context7.com/ranchero-software/netnewswire/llms.txt Illustrates how to use the Account class to manage individual feed accounts, including creating feeds and folders, moving feeds between containers, and fetching articles based on various criteria like feed, unread status, date, or search terms. It also covers marking articles and importing OPML subscriptions. ```swift import Account import Articles // Access default local account let localAccount = AccountManager.shared.defaultAccount // Create a new feed localAccount.createFeed( url: "https://example.com/feed.xml", name: "Example Feed", container: localAccount, validateFeed: true ) { result in switch result { case .success(let feed): print("Created feed: \(feed.nameForDisplay)") case .failure(let error): print("Error: \(error)") } } // Create a folder for organizing feeds let folder = try await localAccount.addFolder("Technology") // Move a feed to the folder if let feed = localAccount.existingFeed(withURL: "https://example.com/feed.xml") { localAccount.moveFeed(feed, from: localAccount, to: folder) { result in if case .success = result { print("Feed moved to folder") } } } // Fetch articles from a specific feed if let feed = localAccount.existingFeed(withFeedID: "feed-id") { let articles = try localAccount.fetchArticles(.feed(feed)) for article in articles { print("\(article.title ?? "Untitled") - \(article.status.read ? "Read" : "Unread")") } } // Fetch unread articles with a limit let recentUnread = try localAccount.fetchArticles(.unread(50)) // Fetch today's articles let todayArticles = try localAccount.fetchArticles(.today()) // Fetch starred articles let starredArticles = try localAccount.fetchArticles(.starred()) // Search articles let searchResults = try localAccount.fetchArticles(.search("Swift programming")) // Mark articles as read/starred localAccount.markArticles(Set(articles), statusKey: .read, flag: true) { _ in } localAccount.markArticles(Set(articles), statusKey: .starred, flag: true) { _ in } // Trigger refresh for this account try await localAccount.refreshAll() // Import OPML subscriptions localAccount.importOPML(opmlFileURL) { result in switch result { case .success: print("OPML imported successfully") case .failure(let error): print("Import failed: \(error)") } } ``` -------------------------------- ### Data Persistence using Dot Notation Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSCore/Tests/RSCoreTests/Resources/inessential.txt Demonstrates the concept of persistent data storage using a hash-table-based database structure, where values are stored and retrieved via simple dot notation without explicit serialization. ```text user.prefs.city = "Seattle" ``` -------------------------------- ### Fetch and Open RSS Feeds in BBEdit Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/sixcolors.html Downloads an XML feed to a file and immediately opens it in the BBEdit text editor using a chained command. ```bash curl http://feeds.theincomparable.com/tpk > tpk.rss ; bbedit tpk.rss ``` -------------------------------- ### Create GitHub Release from Tag Source: https://github.com/ranchero-software/netnewswire/blob/main/Technotes/HowToDoiOSTestFlightRelease.markdown This command shows how to create a new release on GitHub using an existing Git tag. This is typically done after pushing the tag to the remote repository and is often the final step in the release process on GitHub. ```bash gh release create iOS-6.1.5-6124 --title "NetNewsWire 6.1.6 (6140) for iOS - TestFlight" --notes "Release notes content here" ``` -------------------------------- ### Polymer Ready Event Listener in JavaScript Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html This code sets up an event listener for the 'script-load-dpj' event to handle Polymer's readiness. Once the event fires or if Polymer is already ready, it logs performance ticks using `ytcsi`. This is crucial for ensuring Polymer components are initialized before further actions are taken. ```javascript var onPolymerReady = function(e) {window.removeEventListener('script-load-dpj', onPolymerReady);if (window.ytcsi) {window.ytcsi.tick('apr', null, '');}}; if (window.Polymer && Polymer.RenderStatus) {onPolymerReady();} else {window.addEventListener('script-load-dpj', onPolymerReady);} ``` -------------------------------- ### Implement Virtual Feeds with SmartFeed in Swift Source: https://context7.com/ranchero-software/netnewswire/llms.txt Explains the implementation of virtual feeds like 'Today', 'All Unread', and 'Starred' using the SmartFeed class. It covers accessing built-in smart feeds, their properties, fetching articles (synchronously and asynchronously), and creating custom smart feeds with a delegate. ```swift import Account import Articles // Smart feeds are typically accessed through SmartFeedsController let smartFeedsController = SmartFeedsController() // Access built-in smart feeds let todayFeed = smartFeedsController.todayFeed let unreadFeed = smartFeedsController.unreadFeed let starredFeed = smartFeedsController.starredFeed // Smart feed properties print("Name: \(todayFeed.nameForDisplay)") print("Unread Count: \(todayFeed.unreadCount)") print("Icon: \(todayFeed.smallIcon?.description ?? "Default")") // Fetch articles from smart feed let todayArticles = try todayFeed.fetchArticles() print("Today's articles: \(todayArticles.count)") // Async fetch let unreadArticles = try await unreadFeed.fetchArticlesAsync() print("Unread articles: \(unreadArticles.count)") // Fetch only unread from smart feed let filteredArticles = try starredFeed.fetchUnreadArticles() // Custom SmartFeed with delegate class CustomSmartFeedDelegate: SmartFeedDelegate { var sidebarItemID: SidebarItemIdentifier? { nil } var nameForDisplay: String { "Custom Feed" } var smallIcon: IconImage? { nil } func fetchArticles() throws -> Set
{ // Custom article fetching logic return try AccountManager.shared.fetchArticles(.unread(100)) } func fetchUnreadCount(account: Account) async throws -> Int { return try await account.fetchUnreadCountForTodayAsync() } } let customFeed = SmartFeed(delegate: CustomSmartFeedDelegate()) ``` -------------------------------- ### Save Web Content to Desktop Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/sixcolors.html Downloads a remote file directly to the user's Desktop directory. ```bash curl http://feeds.theincomparable.com/tpk > ~/Desktop/tpk.rss ``` -------------------------------- ### POST /youtubei/v1/playlist/create Source: https://github.com/ranchero-software/netnewswire/blob/main/Modules/RSParser/Tests/RSParserTests/Resources/YouTubeTheVolvoRocks.html This endpoint is used to create a new playlist containing a specific set of videos. ```APIDOC ## POST /youtubei/v1/playlist/create ### Description Creates a new playlist and populates it with an initial set of video IDs. ### Method POST ### Endpoint /youtubei/v1/playlist/create ### Request Body - **videoIds** (array) - Required - List of video IDs to include in the new playlist. - **params** (string) - Optional - Additional configuration parameters. ### Request Example { "videoIds": ["qCTCOMSEsHM"], "params": "CAQ%3D" } ### Response #### Success Response (200) - **playlistId** (string) - The ID of the newly created playlist. #### Response Example { "playlistId": "new_playlist_id_123" } ```