Ben Dodson

Freelance iOS, macOS, Apple Watch, and Apple TV Developer

Building tools for Kylo Ben

Want to keep up to date? Sign up to my free newsletter which will give you exclusive updates on all of my projects along with early access to future apps.

I’ve been running my Kylo Ben website about video games since October 2016 and this year I decided to start doing a weekly update about gaming news and what I’ve been playing. Whilst it is fun to do, it is very time consuming as I need to collate interesting links I’ve found, my articles, podcasts, game releases, games I’ve played, and games I’ve purchased which means an average post will take between 1.5 to 2 hours to write. Being a developer means I can build my own digital tools to help me out and so last week I built a few little tools to help cut that time dramatically.

One of the bigger pieces of the weekly roundup is a list of interesting news that has happened in the world of video games. Initially I would copy and paste the URLs of interesting links I found and save them into the Notes app1 on iOS or Mac. This worked fine but it was a little clunky and getting the data back out took time as I’d need to open each one to see what it was and then add Markdown syntax to each URL I wanted to use. To solve this, I wrote an iOS app and a macOS app that would provide extensions for URLs allowing me to quickly save them to my database.

[app name] would like to access Apple Music

The iOS app is purely a blank view controller with a bundled share extension that looks a little like this2:

class ShareViewController: SLComposeServiceViewController {

    override func isContentValid() -> Bool {
        return true
    }

    override func didSelectPost() {
        if let item = extensionContext?.inputItems.first as? NSExtensionItem, let itemProvider = item.attachments?.first as? NSItemProvider {
            if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
                itemProvider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (url, error) in
                    if let shareURL = url as? URL {
                        APIClient.post("save", parameters: ["url": shareURL.absoluteString, "title": self.textView.text], onCompletion: { (error, response) in
                            if let error = error {
                                let controller = UIAlertController(title: "ERROR", message: "That didn't work: \(error.localizedDescription)", preferredStyle: .alert)
                                controller.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
                                    self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
                                }))
                                self.present(controller, animated: true, completion: nil)
                            } else {
                                self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
                            }
                        })
                    }
                })
            }
        }
    }

    override func configurationItems() -> [Any]! {
        return []
    }

}

This is paired with an NSExtensionActivationSupportsWebURLWithMaxCount entry in the Info.plist file so that it will activate whenever I try and share a URL anywhere within iOS. If I’m in an app reading an article that I want to save, I simply tap the share icon and then choose the Kylo Ben app from the list as shown in the screenshot above. The URL and title will then be sent to my server for retrieval later on.

[app name] would like to access Apple Music

I’ve written a number of Safari extensions in JavaScript before but El Capitan added the option to write native extension in Swift via a Safari Extension bundled with your macOS app. To avoid having to make AJAX calls in JavaScript3, I chose to build a simple macOS app with a Safari Extension that looks like this:

class SafariExtensionHandler: SFSafariExtensionHandler {
    
    override func toolbarItemClicked(in window: SFSafariWindow) {
        window.getActiveTab { (tab) in
            tab?.getActivePage(completionHandler: { (page) in
                page?.getPropertiesWithCompletionHandler({ (properties) in
                    if let properties = properties, let url = properties.url {
                        let title = properties.title ?? "Unknown Title"
                        APIClient.post("save", parameters: ["url": url.absoluteString, "title": title], onCompletion: { (error, response) in
                            if let error = error {
                                NSLog("PROBLEM! \(error)")
                            } else {
                                page?.reload()
                            }
                        })
                    }
                })
            })
        }
    }

}

When I click on the controller icon, the method above is called and the URL and title are sent to my server; once completed, the page reloads to show me it has been successful. I spent a long time trying to just get a simple alert to display on either success or failure but I couldn’t get it to work correctly. It is possible to interact with JavaScript and I was able to log to the console but any alert would silently fail. If anybody has any tips on that, I’d love to know how to improve it.

The basic template of my weekly update is the same every week and I used to use a number of custom MySQL queries to pull out the various information I needed and then write it up manually. Now that I have my links stored in my database, I decided to write a PHP script to generate as much of my update as possible so all I need to do is fill in some of the blanks that aren’t automatically provided (i.e. upcoming game release dates) and write my own thoughts and opinions around the news articles. I have a basic PHP script which runs a number of MySQL queries and then generates a Markdown document like this:

Introduction...

###News

[Final Fantasy 15's PS4 Pro Update Out Now, Improves Frame Rate And More - GameSpot](http://www.gamespot.com/articles/final-fantasy-15s-ps4-pro-update-out-now-improves-/1100-6448025/)

[New PlayStation 4 Pro patch for Final Fantasy XV makes it look worse | Ars Technica](https://arstechnica.com/gaming/2017/02/new-playstation-4-pro-patch-for-final-fantasy-xv-makes-it-look-worse/#p3)

[This tiny Nintendo Switch feature is already making fans super happy - Polygon](http://www.polygon.com/2017/2/20/14668988/nintendo-switch-click-sound-effect-joy-con)

[Alto's Odyssey awaits, Summer 2017](http://blog.builtbysnowman.com/post/157488116747/altos-odyssey-summer-2017)

[never gonna give you up - What’s In the Box?2?! Take 2](http://tyrod.com/post/157494246009/whats-in-the-box2-take-2)

[Steam Community :: Group Announcements :: Orwell](http://steamcommunity.com/games/491950/announcements/detail/484538095747263770)

[Nintendo tag teams with John Cena for living room-inspired Switch demos - Polygon](http://www.polygon.com/2017/2/21/14682742/nintendo-switch-john-cena)

[Look What Mega Bloks Is Doing To Pokémon ](http://kotaku.com/look-what-mega-bloks-done-to-pokemon-1792555348)

[Pillars of Eternity 2 campaign clears $3 million - Polygon](http://www.polygon.com/2017/2/21/14689394/pillars-of-eternity-2-deadfire-funded-3-million-fig)

[Take a look at how itty-bitty the Nintendo Switch cartridge is - Polygon](http://www.polygon.com/2017/2/21/14691596/nintendo-switch-cartridge-size-comparison)

[Australia Is Coming To Civilization VI](http://kotaku.com/australia-is-coming-to-civilization-vi-1792599435)

[Rocket League Original Minis toys expanding with light-up cars - Polygon](http://www.polygon.com/2017/2/21/14692528/rocket-league-original-minis-light-up-cars)

[Hot and heavy Mass Effect pack comes to Cards Against Humanity - Polygon](http://www.polygon.com/2017/2/22/14698798/cards-against-humanity-mass-effect-pack)

And finally, 

###My Posts
- Making the earth move with Stagehand — "I really like the premise of a "reverse platformer" but there simply isn't enough content to keep me coming back when it is stood next to _Tiny Wings_, _Alto's Adventure_, and _Super Mario Run_" [[link](https://kyloben.co.uk/stagehand-review)]

###Podcasts
- Podcast #xx: Title [[link]()]
- Another Podcast #xx: Title [[link]()]

###Upcoming Game Releases
- _Game Title #1_ (date - platforms) [[link]()]
- _Game Title #2_ (date - platforms) [[link]()]
- _Game Title #3_ (date - platforms) [[link]()]
- _Game Title #4_ (date - platforms) [[link]()]
- _Game Title #5_ (date - platforms) [[link]()]

###Gaming Time
This week I spent 9.6 hours playing six different games:

- **Stagehand** (0.5hrs): Text...
- **Rocket League** (0.6hrs): Text...
- **Pokémon Moon** (0.7hrs): Text...
- **Forza Horizon 3** (1.1hrs): Text...
- **SteamWorld Heist** (2.8hrs): Text...
- **Night in the Woods** (3.9hrs): Text...

This week I added 2 new games to my library: _Crusader Kings II_, _Night in the Woods_.

Details on games I'm planning on playing this week...

Until next time, have a great week!

---

_Did you enjoy this weekly roundup? Make sure you don't miss one by subscribing to [Kylo Ben Weekly](https://kyloben.co.uk/weekly) - it's this post in email form every Monday!_

The news URLs are simply pulled from the database and wrapped up so that each link uses the title of the page as provided by the macOS and iOS extensions. I will nearly always change the link title (as it’ll be part of a sentence) but it allows me to quickly see what an article is about without needing to open it up and re-read it. The “my posts” section requires no editing at all as it pulls the title, link, and a pull quote directly from the articles I’ve published in the previous week. The podcasts and upcoming game release sections can’t be automatically populated (yet) so I just use placeholder text for these to reduce the amount of effort required. The final section on my gaming time uses a number of queries to get the exact amount of time I’ve spent playing in the past week, adds placeholders for each game so I can write about them, and then lists out any new games I’ve added to my library; all of this is thanks to some scripts I wrote a while back that scrape my Steam and Xbox One libraries to track changes and allow me to render a page showing my gaming time for the past few months.

Once I’ve finished writing, the Markdown file is uploaded to my server and the weekly update will then appear on the website. I then use Byword’s “copy as HTML” feature to generate a HTML version and use that with Mailchimp to write and send out the email version of the update.

With these tools, I can now write my weekly update pretty quickly and only have to focus on what I want to say rather than spending time on copying, pasting, and formatting. If you’re interested in video games, sign up to the weekly email as it is the best way to get a digest of what has been happening over the past week as well as seeing what new games are arriving.

  1. I could have used a service like Pocket to do this but then I’d have to either use two Pocket accounts or fill my personal account with links that I don’t want to read later. ↩︎

  2. This is not what I would call production code quality so don’t just wildly copy and paste this into an app or you’ll likely regret it. Works well enough for my own personal use though! ↩︎

  3. Which is a nightmare when you start hitting cross domain restrictions. ↩︎

AlcoPath » « Proposal for an Erase Data Passcode

Want to keep up to date? Sign up to my free newsletter which will give you exclusive updates on all of my projects along with early access to future apps.