{"id":3110,"date":"2014-12-30T11:26:50","date_gmt":"2014-12-30T16:26:50","guid":{"rendered":"http:\/\/www.migrate.edwardbacon.com\/blog\/?p=3110"},"modified":"2014-12-30T11:37:13","modified_gmt":"2014-12-30T16:37:13","slug":"workflow-to-retrieve-movie-data-as-markdown-text-3","status":"publish","type":"post","link":"https:\/\/www.edwardbacon.com\/blog\/2014\/12\/workflow-to-retrieve-movie-data-as-markdown-text-3\/","title":{"rendered":"Workflow to Retrieve Movie Data as MarkDown Text"},"content":{"rendered":"<p>Last week, I used up an iTunes gift card to get copies of <a title=\"Workflow | Powerful automation made simple.\" href=\"https:\/\/my.workflow.is\/\">Workflow<\/a> and <a title=\"Editorial for iOS\" href=\"http:\/\/omz-software.com\/editorial\/\">Editorial<\/a> for iOS. In order to become familiar with the iOS Workflow application, I gave myself a little assignment to create a workflow that would retrieve the IMDB information for a movie, create some markdown text and create a new draft in <a title=\"Drafts - Agile Tortoise\" href=\"http:\/\/agiletortoise.com\/drafts\/\">Drafts<\/a>. I then created this blog post completely on my iPad using Editorial , thanks to <a title=\"Reinventing iOS Automation: Editorial Review \u2013 MacStories\" href=\"http:\/\/www.macstories.net\/stories\/editorial-for-ipad-review\">Federico Viticci&#8217;s<\/a> excellent primer and actions.<\/p>\n<p>You can get my movie workflow <a title=\"Movie to Drafts\" href=\"https:\/\/workflow.is\/workflows\/505b2a9723fe4b9f9fd7641edfdf04b1\">here<\/a>.<\/p>\n<h2>Using the Movie workflow<\/h2>\n<p>The workflow requires you have Drafts on your device.<br \/>\nUser steps:<\/p>\n<ul>\n<li>Enter the movie Title;<\/li>\n<li>Optionally enter the year.<\/li>\n<li>Optionally rate the movie.<\/li>\n<li>Select some descriptive movie tags for the entry.<\/li>\n<\/ul>\n<p>The Drafts app will open, containing a new draft with markdown text for the movie. You can then use a drafts action to create a entry in <a title=\"Day One | A simple and elegant journal for iPhone, iPad, and Mac.\" href=\"http:\/\/dayoneapp.com\/\">DayOne<\/a> or a note in <a title=\"The workspace for your life\u2019s work | Evernote\" href=\"https:\/\/evernote.com\/\">Evernote<\/a>.<\/p>\n<h2>Variations on a theme<\/h2>\n<p>My original goal for the workflow was to directly create a DayOne entry. I had a bit of trouble with <code>Open X-callback URL<\/code> (see below), and well, I rationalized that creating a draft is more flexible.<\/p>\n<p>From Drafts, one can define an action to create a DayOne entry or create an Evernote note, or an action that does both. It is simple enough to modify the last step to call the appropriate Drafts action.<\/p>\n<p>Another varient I wrote grabs the title from the clipboard and works as an extension. So for example, you could highlight the name of a movie in Safari and run the workflow from the Sharing menu. This is a pretty straight forward change to the begining of the workflow, and as such, is left to the reader<sup id=\"fnref1\"><a href=\"#fn1\" rel=\"footnote\">1<\/a><\/sup>.<\/p>\n<p>Finally, I have added this workflow as an action in Launch Center Pro. Whether I come across a #MovieToWatch later or one I just saw an want to remember and rate, I simply slide to the LCP action.<\/p>\n<h2>Details of the Movie workflow<\/h2>\n<p>This section represents notes to myself on the workflow implementation. My main intention was to discover how Workflow works, you may find some of what follows useful, or not.<\/p>\n<p>The workflow is made up of the following sections:<\/p>\n<ol>\n<li>Capture Title and Year<\/li>\n<li>Query IMDB for Title and Year<\/li>\n<li>Parse JSON data in a dictionary<\/li>\n<li>Get user rating and tags<\/li>\n<li>Store IMDB data in variables<\/li>\n<li>Create markdown text<\/li>\n<li>Create text in target (Drafts)<\/li>\n<\/ol>\n<h3>Capture Title and Year<\/h3>\n<p>This is pretty straight forward prompt for each and store the strings in variables. A varient would be to get the <em>title<\/em> from the clipboard and not prompt for it, this avoids query errors from user typos.<\/p>\n<h3>Query IMDB for Title and Year<\/h3>\n<p>Use <code>URL<\/code> to create the query string and then <code>Get Contents of URLs<\/code> to call the web-service. The result of the IMDB query is JSON data, and stored in the variable <em>imdbJson<\/em>. If the query failed, the result will contain <em>\u201cResponse\u201d:\u201cFalse\u201d<\/em>, in which case the user is promted to continue or not.<\/p>\n<h3>Parse JSON data in a dictionary<\/h3>\n<p>The result of the IMDB query is JSON data, a series of <em>\u201ckey\u201d:\u201cvalue\u201d<\/em> substrings. <code>Get Dictionary from Input<\/code> parses <em>imdbJson<\/em> into a dictionary variable, <em>imdbRes<\/em>. The other string variables are initially cleared out.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"Parse JSON data into a dictionary\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_104815.png?w=1170\" alt=\"Parse JSON data into a dictionary\" \/><\/p>\n<h3>Get user rating and tags<\/h3>\n<p>This section of the workflow provides examples of using <code>Menu<\/code> and <code>List<\/code> . <code>Menu<\/code> prompts the user to choose a path of execution. In this case, it is to rate the movie or not. A <code>List<\/code> of possible ratings is presented and a single rating is select using <code>Choose from List<\/code> and simply stored in a variable.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"Menu and single item selection from list\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_105946.png?w=1170\" alt=\"Menu and single item selection from list\" \/><\/p>\n<p>For the movie tags a <code>List<\/code> of tags is presented, this time with the <em>Select Multiple<\/em> option in <code>Choose from List<\/code> To capture all of the selected movie tag values, iterate of the list and append it to the <em>movieTags<\/em> variable. The key here is to realize that <code>Input<\/code> holds the value of the current iteration of <code>Repeat with Each<\/code>; I found it helpful to \u201cthink like you are a processing stack\u201d. At the start all of the values are pushed onto a stack. In each iteration <code>Input<\/code> becomes the top of the stack holding the value of one item. Each step of the loop concatenates <em>movieTags<\/em> with <code>Input<\/code> using <code>Combine Text<\/code> and stores the result in the accumulator\/variable <em>movieTags<\/em>. At the bottom of the loop, the stack is \u201cpopped\u201d and the next value on the stack is set to <code>Input<\/code>. N.B. if you would assign to a variable after the <code>Repeat with Each<\/code> block the value is the last item of the list, that is the last value of <code>Input<\/code><sup id=\"fnref2\"><a href=\"#fn2\" rel=\"footnote\">2<\/a><\/sup>.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"Iterate over list and concatenate values\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_105626.png?w=1170\" alt=\"Iterate over list and concatenate values\" \/><\/p>\n<h3>Store IMDB data in variables<\/h3>\n<p>Rather than scan the string directly returned by the web service, <em>imdbJson<\/em>, use dictionary variable, <em>imdbRes<\/em> to lookup values for each key . <code>Get Value for Key<\/code>finds a key in the dictionary and returns the associated value which is then stored in a similarly named variable.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"Lookup keys in dictionary imdbRes\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_104231.png?w=1170\" alt=\"Lookup keys in dictionary imdbRes\" \/><\/p>\n<h3>Create markdown text<\/h3>\n<p>Pretty straight forward concatenation of variables and markdown text.<\/p>\n<h3>Create text in target<\/h3>\n<p>I would like to take the resulting markdown text and use it as <code>Input<\/code> to a block to create an entry in another application. For Drafts it is pretty simple to use <code>Create Draft<\/code>. Specify a <em>Run Action<\/em> or to <em>Edit in Drafts<\/em>, either works well.<br \/>\n<img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"Markdown text to Drafts\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_112348.png?w=1170\" alt=\"Markdown text to Drafts\" \/><\/p>\n<p>For DayOne, I formed a <code>URL<\/code> using <em>dayone:\/\/post?entry=<code>Input<\/code><\/em> and invoked DayOne via <code>Open X-callback URL<\/code>. This creates an entry in DayOne, but <code>Open X-callback URL<\/code> never returns and the workflow never ends. Perhaps I am missing something here.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" title=\"x-callback failed to return\" src=\"https:\/\/i0.wp.com\/www.migrate.edwardbacon.com\/blog\/wp-content\/uploads\/ios\/_img_WorkflowCapturingMovieData_2014_12_30_111458.png?w=1170\" alt=\"x-callback failed to return\" \/><\/p>\n<p>For Evernote, I thought I would convert the markdown to Rich Text and create a new note in Evernote, but <code>Make Rich Text from Markdown<\/code> crashed the Workflow app. These issues are why I have settled on creating a draft and running an action it.<\/p>\n<h2>More ideas<\/h2>\n<p>I am not sure what is possible here, so the next experiments for me :<\/p>\n<ul>\n<li>Make the code that parses the IMDB string as a separate workflow. Then chain that with separate \u201cinput\u201d and \u201coutput target\u201d workflows.<\/li>\n<li>Detect different ways the workflow was invoked and if as an extensiopn getting title from clipboard, otherwise prompt for title.<\/li>\n<\/ul>\n<h2>Thoughts on the Workflow UI<\/h2>\n<p>I have always cringed a little with a drag and drop UI to create control programs. This goes back to working with similar applications running on an <em>Amiga<\/em>. I get the idea that these applications are targeted for non-programers, allowing them to quickly become productive. I have no problem with that, well at least until the workflow needs to be \u201cproduction quality\u201d and grows in complexity. My sample is a quite long linear string of instructions and I found pretty hard to maintain.<\/p>\n<p>The paradox of an intuitive, simple UI is that it can sometimes be perplexing. Often when scrolling screen through the workflow, my stubby, slightly arthretic fingers ended up moving an instuction and in effect unintentionally editing my workflow. When I did want to move something like a long <code>IF<\/code> control containing many steps in its \u201cclauses\u201d, the screen jumped around wildly and I felt as if I had no control of where the block would end up. In fact most often I had no idea to where it actualy moved. I found myself frequently sharing the workflow to Evernote, so that I could recover from accidental edits.<\/p>\n<p>Really I am not complaining, just recording issues with which I had to deal. This was meant as a discovery exercise and was heavily influenced by some personal bias. I also recognize that there are other apps with more sophisticated programing\/scripting capabilities. I think the Workflow app provides a great means to combine and control iOS apps. I think this has tremendous utility and power in it.<\/p>\n<h3>Some feature suggestions<\/h3>\n<ul>\n<li>Allow locking a workflow against edits, or have a \u201cview mode\u201d and \u201cedit mode\u201d.<\/li>\n<li>Provide means to duplicate a workflow.<\/li>\n<li>Provide a means to locally backup a workflow under development<\/li>\n<li>Provide a way to collapse long nested blocks to promote readability and moving them.<\/li>\n<li>Provide a way to add comments.<sup id=\"fnref3\"><a href=\"#fn3\" rel=\"footnote\">3<\/a><\/sup><\/li>\n<\/ul>\n<div class=\"footnotes\">\n<hr \/>\n<ol>\n<li id=\"fn1\">You can take the math teacher out of the classroom, but you cannot take the teacher of the mathematician.\u00a0<a href=\"#fnref1\" rev=\"footnote\">\u21a9<\/a><\/li>\n<li id=\"fn2\">There is an easier way to find the last item however.\u00a0<a href=\"#fnref2\" rev=\"footnote\">\u21a9<\/a><\/li>\n<li id=\"fn3\">Old-school stuff I know, but this is a control language, not self-documenting object code.\u00a0<a href=\"#fnref3\" rev=\"footnote\">\u21a9<\/a><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Last week, I used up an iTunes gift card to get copies of Workflow and Editorial for iOS. In order to become familiar with the iOS Workflow application, I gave myself a little assignment to create a workflow that would retrieve the IMDB information for a movie, create some markdown text and create a new [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[21,13],"tags":[531,529,530],"class_list":{"0":"post-3110","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-general-interest","7":"category-tips","8":"tag-coding","9":"tag-ios","10":"tag-workflow","11":"czr-hentry"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1FUJv-Oa","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/posts\/3110","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/comments?post=3110"}],"version-history":[{"count":0,"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/posts\/3110\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/media?parent=3110"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/categories?post=3110"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.edwardbacon.com\/blog\/wp-json\/wp\/v2\/tags?post=3110"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}