Creating a script to post to Facebook

Hi,

I’ve written a script to post to Facebook which links to four different shortcuts in the Shortcuts app, the one chosen depending on which option is selected by the user. I created four separate shortcuts to accommodate the vagaries of the Shortcuts app (e.g. there is no action to convert a video type) and the Post on Facebook action (e.g. it’s not possible to do inline tagging or add captions to media). Although the script seems to be functioning well, if the Facebook action is called from the share sheet, but is then cancelled, the Drafts app crashes.

https://www.icloud.com/shortcuts/5b395032b78c4c398624aab13315cb15
https://www.icloud.com/shortcuts/19868122b4c9424c9567e5f887a0edaa
https://www.icloud.com/shortcuts/165ea24526834890b812c07042ee7549
https://www.icloud.com/shortcuts/3ec3bc18478b42e889de27b9f3268a24


var text = "false";

(() => {

let cb = CallbackURL.create();
cb.baseURL = "shortcuts://x-callback-url/run-shortcut";

let p = Prompt.create();
var options = ["Captions", "Inline tagging", "Photos (no videos)", "Videos [with photos]"];
var selectedOptions = [""];

p.addSelect("s", "Will your post contain any of the following elements?", options, selectedOptions, true);

p.addButton("OK");

if (!p.show()) {
      context.cancel();
      return;}
else {
if (p.fieldValues['s'] == 'Photos (no videos)');
 cb.addParameter("name", "Post to Facebook (1)");
if (p.fieldValues['s'] == 'Captions'||'Inline tagging'&&'Photos (no videos)');
 cb.addParameter("name", "Post to Facebook (2)");
if (p.fieldValues['s'] == 'Videos [with photos]');
 cb.addParameter("name", "Post to Facebook (3)");
if (p.fieldValues['s'] == 'Captions'||'Inline tagging'&&'Videos [with photos]');
 cb.addParameter("name", "Post to Facebook (4)");
if (p.fieldValues['s'] == ''){
text = "true";}
 
 let success = false;
  if (text == "true"){
    success = Share.shareAsText(draft.processTemplate("[[draft]]"));
  } else {
    success = app.openURL(cb.url);
  }
  return true;
      }
if (success) {
    console.log("Posted to Facebook");
  } else {
    console.log(cb.status);
    if (cb.status == "cancel") {
      context.cancel();
    } else {
      context.fail();
    }
  }
})()

The script is preceded by an action step that copies the contents of the draft to the clipboard.

Any thoughts on this issue, or on the script/shortcuts in general, are most welcome.

Thanks,

Martin

I have discovered problems with the section of code letting the user choose from the four options. It doesn’t matter which option(s) is/are selected, the shortcut always defaults to the last option (Post to Facebook (4)), unless no options are selected, in which case the text is copied to the clipboard and the share sheet opened as requested.

I have spotted two errors and corrected them: I have defined selectedOptions as an array, and I have added curly brackets within the if statements.

Can anyone show me where I’m going wrong?

Thanks,

Martin

Your if statement constructs are not correct and are falling through. Try using else if and always wrap the code to be executed by the if condition in braces for clarity, like:

if (!p.show()) {
      context.cancel();
      return;}
else {
    let selected = p.fieldValues['s'][0];
    if (selected == 'Photos (no videos)') {
        cb.addParameter("name", "Post to Facebook (1)");
    }
    else if (selected == 'Captions'||'Inline tagging'&&'Photos (no videos)') {
        cb.addParameter("name", "Post to Facebook (2)");
    }
    else if (selected == 'Videos [with photos]') {
        cb.addParameter("name", "Post to Facebook (3)");
    }
    else if (selected == 'Captions'||'Inline tagging'&&'Videos [with photos]') {
        cb.addParameter("name", "Post to Facebook (4)");
    }
    else if (selected == '') {
        text = "true";
    }
}
1 Like

@agiletortoise Thanks for this.

I’ve updated the code (below) and also made some changes to the options to simplify things. My problem is that the first two options execute as expected, but the rest don’t.

let cb = CallbackURL.create();
cb.baseURL = 'shortcuts://x-callback-url/run-shortcut';

let p = Prompt.create();
let options = ['Captions and/or inline tagging', 'Photos', 'Videos'];
let selectedOptions = [];

  p.addSelect('s', 'Will your post contain any of the following elements?', options, selectedOptions, true);

  p.addButton('OK');

  if (!p.show()) {
      context.cancel();
      return;}
  else {
    let selected = p.fieldValues['s'][0];
    
    if (selected == 'Captions and/or inline tagging' || !('Photos' || 'Videos'))
    {captionsTags = 'true';}
    else if (selected == 'Photos')
    {cb.addParameter('name', 'Post to Facebook (1)');}
    else if (selected == 'Captions and/or inline tagging' && 'Photos')
    {cb.addParameter('name', 'Post to Facebook (2)');}
    else if (selected == (!'Captions and/or inline tagging' && 'Videos') || (!'Captions and/or inline tagging' && 'Photos' && 'Videos'))
    {cb.addParameter('name', 'Post to Facebook (3)');}
    else if (selected == (('Captions and/or inline tagging' && 'Videos') || ('Captions and/or inline tagging' && 'Photos' && 'Videos')))
    {cb.addParameter('name', 'Post to Facebook (4)');}
    else if (selected == ''){text = 'true'};
  }
 
 let captionsTags = 'false';
 let success = false;
 let text = 'false';
   if (captionsTags == 'true'){
   success = app.openURL('fb://');
   } else if (text == 'true'){
   success = Share.shareAsText(draft.processTemplate('[[draft]]'));
   } else {
   success = app.openURL(cb.url);
   }
  return true;
})()

These are the expected outcomes based on what the user selects:

  • ‘Captions and/or inline tagging’ = Facebook
  • ‘Photos’ = ‘Post to Facebook(1)’
  • ‘Captions and/or inline tagging’ AND ‘Photos’ = ‘Post to Facebook (2)’
  • ‘Photos’ AND/OR ‘Videos’ NO ‘Captions and/or inline tagging’ = ‘Post to Facebook (3)’
  • ‘Photos’ AND/OR ‘Videos’ AND ‘Captions and/or inline tagging’ = ‘Post to Facebook (4)’
  • No selection = Share Sheet

I clearly haven’t got the hang of logical operators!

Any help much appreciated.

Martin

Yes, I would recommend you review some control flow basics in JavaScript. Eloquent Javascript is a great book, and available online, to get up to speed on these things quickly.

You have logical constructs like (a == b || c), where you really want (a == b || a == c), etc. Logical (&& ||) operators will be evaluated before your equivalency operator (==).

1 Like

@agiletortoise This book looks excellent. I have read some of its content (and will continue to read more); however, I’m still completely baffled as to why it’s so difficult to execute such a seemingly simple statement as the following, for example:

If the user selects A and ONLY A from A, B, and C, then do this.

I’ve experimented with seemingly endless variations of the logical operators and am getting nowhere. I just cannot get it to be exclusive to A.

:weary:

  • Have you tried putting it towards the bottom of your if/else if/else list?
  • Have you tried simplifying it down to say just a manually populated array (no prompt use), with A and B so you can work on the logic more easily?

As was noted above your starting point incorporated a lot of flawed logic.

A good approach is to take a step back, and build up from the basics. Start with an array. Go for if A else B first. Then try if A and B. Then try combining them - if A and B, else if A, else if B, else neither A or B.

After that expand it to C, and after that hopefully you’ll have enough clarity to build.it into your script.

1 Like

I think you have a misunderstanding of how logical operators interact with data types. I missed in my original feedback that you were looking at multiple values, not just a single select value. The “selected” options value from a multi-select result is an array, and using ==, &&, || on arrays do not compare against individual values in the underlying array. You need something more the below, that is testing for whether the array includes a value.

let selected = p.fieldValues['s'] // this is an array of values
if ( selected.includes('Captions and/or inline tagging') && !(selected.includes('Photos') || selected.includes('Videos')) ) {
   // ... do something
}
1 Like

@sylumer I simplified my logic as you suggested, and this did help matters.

@agiletortoise I actually realised this before you posted, and my solution was to output as a string and test against that. This worked; however, I think your suggestion is more elegant, and I shall go with that, I think!

Many thanks.