0

I'm an independent publisher on Apple News, and create articles using News Publisher. I was looking for some flexibility in how my articles are formatted and presented, and was wondering how to upload a JSON document for future articles - I've never worked with it before.

How can I connect something like this to Apple News? I looked at their help section already, but came away with more questions than answers it seems.

halfer
  • 19,824
  • 17
  • 99
  • 186
TCharb
  • 444
  • 1
  • 6
  • 15

1 Answers1

3

A basic article looks like this

{
    "version": "1.4",
    "identifier": "sketchyTech_Demo",
    "title": "My First Article",
    "language": "en",
    "layout": {},
    "components": [
        {
            "role": "title",
            "text": "My First Article"
        },    
        {
            "role": "body",
            "text": "This is just over the minimum amount of JSON required to create a valid article in Apple News Format. If you were to delete the dictionary enclosing this text, you'd be there."
        }
    ],
    "componentTextStyles": {}
}

and is always saved as article.json. Within the components array you can feature any of the Apple News Components. (Note: You needn't use pure json, you can use markdown or html instead for the text in order to simplify styling.)

I put together this more extensive set of samples on GitHub and you will also find details there about testing your articles with News Preview, which will help you by listing errors and so on.

Once you are ready to upload to the service you use the API having first registered to do so, examples of implementing the code are provided in Python. You can upload the article alone or a bundle containing the article and its linked files.

EDITED: Uploading an Article using Python

Copy and paste the following code into a text editor and save as upload.py

#!/usr/bin/python

import requests
import base64
from hashlib import sha256
import hmac
from datetime import datetime
import glob
import argparse
import os
import mimetypes
from requests.packages.urllib3.filepost import encode_multipart_formdata
from requests.packages.urllib3.fields import RequestField

arg_parser = argparse.ArgumentParser(description='Publish an article using the Apple News API')
arg_parser.add_argument('article_directory', metavar='ARTICLE_DIR', type=str, help='A directory containing an article.json file and resources')
args = arg_parser.parse_args()

channel_id = '[YOUR CHANNEL-ID]'
api_key_id = '[YOUR API-KEY]'
api_key_secret = '[YOUR API KEY-SECRET]'
method = 'POST'
url = 'https://news-api.apple.com/channels/%s/articles' % channel_id
session = requests.Session()
session.verify = False

def part(filename):
    name = os.path.basename(filename)
    with open(filename) as f:
        data = f.read()
    part = RequestField(name, data)
    part.headers['Content-Disposition'] = 'form-data; filename="%s"; size=%d'  % (name, os.stat(filename).st_size)
    part.headers['Content-Type'] = 'application/json' if name.endswith('.json') else 'application/octet-stream'
    return part

def send_signed_request(method, url, filenames):
    body, content_type = encode_multipart_formdata([part(f) for f in filenames])
    req = requests.Request(method, url, data=body, headers={'Content-Type': content_type})
    req = req.prepare()
    date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    canonical_request = method + url + str(date) + content_type + body
    key = base64.b64decode(api_key_secret)
    hashed = hmac.new(key, canonical_request, sha256)
    signature = hashed.digest().encode('base64').rstrip('\n')
    authorization = 'HHMAC; key=%s; signature=%s; date=%s' % (api_key_id, str(signature), date)
    req.headers['Authorization'] = authorization
    return session.send(req)


response = send_signed_request(method, url, glob.glob('%s/*' % args.article_directory))

print response.status_code
print response.text

Next change the values for the following elements to your own values supplied to you by Apple:

channel_id = '[YOUR CHANNEL-ID]'
api_key_id = '[YOUR API-KEY]'
api_key_secret = '[YOUR API KEY-SECRET]'

Finally open Terminal and drag from Finder the upload.py file you created to the command line, next leave a space before dragging in the folder containing your article.json file so that two paths are displayed next to each other on a single line (the first being the location of the upload.py file and the second being that of the folder containing your article.json file). Finally press Enter.

You should see some returned JSON. Now open News Publisher inside iCloud.com and navigate to Articles > Drafts from CMS for instructions on previewing and publishing the uploaded articles.

sketchyTech
  • 5,746
  • 1
  • 33
  • 56
  • Hey @sketchyTech - sorry for the long absence before getting to this. Thank you for providing such a detailed and comprehensive answer, it really helps. I was confused on getting started (getting the document uploaded), so much appreciated. Is Python knowledge essential in getting that connected? I have the API, but my coding experience is purely front end. – TCharb May 16 '17 at 17:53
  • 1
    You're most welcome. Thank you for marking it as the right answer. In order to assist you in uploading using Python I've added step-by-step instructions. Let me know if you encounter any problems. – sketchyTech May 16 '17 at 18:41
  • Note that it doesn't matter if you send a test article, like the one at the top of my response, because you can delete it from within the iCloud.com News Publisher app. – sketchyTech May 16 '17 at 18:56
  • Just to check in @sketchyTech - it may be worth noting that I don't have my CMS connected to Apple News any longer; I decided to separate the two when I determined I wanted to add special content (images, basic formatting) to my Apple News entries, apart from my website blog. Will this has implications in uploading JSON, if articles are written through the iCloud editor? – TCharb May 16 '17 at 19:16
  • Do you mean you opted out of using your blog's RSS feed in favour of JSON? This is exactly the right thing to have done. You should be good to go. – sketchyTech May 16 '17 at 19:22
  • Just a quick question - does it have to be named upload.py? – TCharb May 17 '17 at 16:27
  • The name of the python file is arbitrary, it is only the name of the `article.json` file which is fixed. – sketchyTech May 17 '17 at 16:59
  • Hey @sketchyTech - getting permission denied when dragging both files into the command line and attempting to execute. I added some componentTextStyles, could that cause an issue, or is the API likely typed incorrectly? Also, does there need to be a layout specified? – TCharb May 30 '17 at 18:29
  • Is permission denied contained in the returned json or is it a warning from the terminal? If the former then it will be something to do with the content or the way it is being uploaded, if it's the latter then it will be to do with the file permissions on your system. You might need to make the python file executable. To do so type `chmod +x ` and then drag in the `upload.py` file (or whatever you've named it) and press enter (making sure there is a space between the `x` and the dragged file path). This gives executable permission to the file. Now try again the above. – sketchyTech May 30 '17 at 18:45
  • That seemed to make the commands executable. However, I received this is response: Traceback (most recent call last): File "/Users/*my admin name*/Documents/Apple News Materials/Coding Resources/upload.py", line 3, in import requests ImportError: No module named requests – TCharb May 30 '17 at 18:58
  • I haven't manipulated the Python document in any way aside from added the IDs and API for News – TCharb May 30 '17 at 19:05
  • Have you included `#!/usr/bin/python` as the top line of the file? – sketchyTech May 30 '17 at 19:58
  • I did, but it does appear sort of greyed out. However, I'm guessing that's just my code editor (Atom). Would it be useful to remove from the file all invalid or non-existent elements as pointed out by the Terminal (i.e. seemingly anything relating to requests)? – TCharb May 30 '17 at 20:00
  • I remember now that I had to install the [requests](http://docs.python-requests.org/en/master/user/install/) module for this to work. Unfortunately, I think you might also need to install `easy_install` or `pip` to actually install `requests` - a complete pain I know and I can't really give any advice on installation aside from checking out the linked info because once done it is quickly forgotten. – sketchyTech May 30 '17 at 20:11
  • Oh dear. Well, I suppose if I have to...is there no other workaround? – TCharb May 30 '17 at 20:25
  • To use Apple's python code no. (I am in the process of completing a small app for macOS for uploading articles to Apple News but unfortunately it's not ready to release yet.) – sketchyTech May 30 '17 at 20:33
  • Gotcha. I found a set of instructions stemming from yours, looks like I need to download XCode and Command Line Tools, PLUS Homebrew. Yikes. Apple News Format needs a baked-in stylesheet that's manipulatable – TCharb May 30 '17 at 20:55
  • I know exactly what you mean. There are plenty of people capable of learning the necessary json but the complexity of the upload makes it difficult for individuals without the tech knowledge to make use of the full Apple News Format. – sketchyTech May 30 '17 at 21:05
  • Out of curiosity, what is `'ARTICLE_DIR'` and how do I specify that? I'm migrating the code to run on Python 3, as my requests via `pip3` are installed properly (and won't on pip), and Terminal says it needs an argument – TCharb May 31 '17 at 17:41
  • The line `arg_parser.add_argument('article_directory', metavar='ARTICLE_DIR', type=str, help='A directory containing an article.json file and resources')` breaks down into the article name, `article_directory`; the name for the argument in usage messages `ARTICLE_DIR`; the type (string); and, the help info. See [here](https://argparse4j.github.io/usage.html#argument-metavar). – sketchyTech May 31 '17 at 17:52
  • So what would I need to plug in there to make the `upload.py` file functional? The only thing I have relating to articles is that `article.json` file you provided me. And I'm a huge noob with Python lol – TCharb May 31 '17 at 18:02
  • The `upload.py` file takes one argument, the argument is the first thing to follow the `upload.py` file location in Terminal and should be the location of a folder containing your `article.json` file and any bundled assets, i.e. images, etc. linked to in your `article.json` file using `bundle://` rather than `https://`or `http://` – sketchyTech May 31 '17 at 18:22