Hype Scriptable Actions (for the Tumult Hype Forum)


If you wonder why the screenshot is on iPhone 6s Plus… yes folks that’s what I still use.

This thread is for JavaScript-based actions to be used with the great and donation based Scriptable iOS-App by Simon Støvring. This extraordinary app integrates with the native APIs of iOS directly from JavaScript. So, you can do all kind of useful stuff.

https://scriptable.app/

How-To:

  • Install the Scriptable app on your phone
  • Install the script by either:
    • Navigating to this post and click on the scriptable file of your choice
    • Creating a new script and copy and pasting the code into it

Latest Posts

This script can show the latest posts using a voice command and opens the Hype Forum when clicked on a post. It is simple and based on the included example script so feel free to post additions and tweaks to it in this thread.

Plain text script for copy and paste into the app:

/**
* Hype ScriptableActions Latest Posts 1.1
* Fetch latest forum posts from Hype Forum
* based on example script and tweaked from there.
*/

let forumURL = "https://forums.tumult.com"
let url = forumURL+"/posts.json"
let req = new Request(url)
let json = await req.loadJSON()
let table = new UITable()
let posts = json.latest_posts
for (i = 0; i < posts.length; i++) {
 let item = posts[i]
 let row = new UITableRow()
 row.onSelect = (idx) => {
    let item = posts[idx]
    Safari.open(forumURL+'/t/'+item.topic_id+'/'+item.post_number)
 }
 let imageURL = item.avatar_template.replace('{size}', 240);
 if (imageURL.indexOf('http')!=0) {
    imageURL = forumURL+imageURL
 }
 let title = item.topic_title
 let subtitle = '@'+item.username+' '+item.name
 let imageCell = row.addImageAtURL(imageURL)
 let titleCell = row.addText(title, subtitle)
 imageCell.widthWeight = 20
 titleCell.widthWeight = 80
 row.height = 80
 row.cellSpacing = 10
 table.addRow(row)
}

QuickLook.present(table)

if (config.runsWithSiri) {
 Speech.speak("Here are the latest posts.")
}

Script.complete()

As scriptable file:
LatestHypeForumPosts.scriptable

3 Likes

Nice,
I have played with scriptable and Pythonista and love them.

Yes, although I didn’t play much with Pythonista… more into JS. Love how we can script iOS with JS. Would love that in export scripts, too. I know, has been discussed before.

Latest Posts Version History:
1.1 - includes links to the forum post (per row) now.

You can, open the script click the pref icon near the bottom , scroll down to the bottom of the pref and you will see a share icon, click and Save to Files or what ever.

I ment Hype Export Scripts in JS :v: … this is an old discussion (JavaScript for automation etc.) not being fully supported etc. Sorry didn't want to reignite that old discussion in this thread.

gah… must be missing something. This presents but does not load. (remains blank)

var wbv = new WebView()

wbv.loadURL(forumURL+'/t/'+item.topic_id+'/'+item.post_number)
wbv.present()

That is totally fine. Maybe some casting or conversion error? Not sure what exactly your doing so limited feedback possible. Are you currently writing it for macOS?

Translatest to using this post as an example …

"https://forums.tumult.com" + '/t/' + '17539' + '/' + '6'

so …

https://forums.tumult.com/t/17539/6

yep, looks correct.

Does it work your end.?

In the iOS-app and as posted above. Yes. But then again I am not using that WebView reference! Only a redirection to iOS Safari as you can see. The discourse forum actually adds the full title into that URL so maybe there is one redirect involved that the WebView isn't following?

Yep all works including Safai load :grinning:

Thats the bit I meant.

Wanted to see if this could be done..?
I put it in place of the Safari.openInApp()
Also I think you can then tal k to the webview DOM via script eval

Not sure what is mean about a WebView but before we get lost in translation. I'd love to see a script on macOS or a WebView version. Kudos for trying.

Ah! Okay. Now I understand your still on iOS. I switched to Safari.open to retain login status and additional functionality. Sorry, just saw that the snippet was updated but the copy and paste part not!

1 Like

Yer probably the best bet as the webview issue looks like something to do with the usual suspects cross origin blah,blah, blah....!
( trick there is a share button when in present, you can share the html, I used that to see whats was actaully in the view)

After playing with getting Hype into Scriptable.

https://forums.tumult.com/t/scriptable-app-and-hype-animations-fun

I came back to this to add a widget which would work on iOS 14.

Note I changed the original's json url file from

let url = forumURL+"/posts.json"

to

const url = forumURL+"/latest.json

which that gets the latest posts and latest poster
I found the other json file listed all lates posts which meant you would see the same users posts in the same thread.


This is done. The widget will list the latest 6 posts.
Clicking on an entry will open the post in Safari.

( Note that Scriptable will flash open first then Safari. This I am made to understand is an iOS thing and cannot be changed or overridden at this time )

You can change that to fit which ever widget size you use.

const widgetPostLimit = 6

Also there is a similar limit to the Table view if the Script is run via Siri or from Scriptable/shortcuts

You can change this to a number instead of the jTopics.length

const tablePostLimit = jTopics.length

You may want to do this for speed.

The table's code has also been changed to reflect the new json.


code:

    // Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-gray; icon-glyph: magic;

const forumURL = "https://forums.tumult.com"
const url = forumURL+"/latest.json"
const req = new Request(url)
const json = await req.loadJSON()
const  imageSize = 48
const widgetPostLimit = 6

//-- user groups
const jUsers = json.users

//-- latest topic groups
const  jTopics = json.topic_list.topics
const tablePostLimit = jTopics.length


//-- Get Latest poster avatar image
function jImage(latestPosterImageID){
    for(var ii = 0; ii < jUsers.length; ii++){
        
        var thisID = jUsers[ii].id
        
        
        if(thisID === latestPosterImageID) {
          
            return jUsers[ii].avatar_template;
        }
    }
}
//

           
//-- Get Latest poster id
function jPoster(jPosters){
    
    
    for(var ii = 0; ii < jPosters.length; ii++){
        
        var thisLatest = jPosters[ii].extras
        
        
        if(thisLatest === 'latest') {
            return  jPosters[ii].user_id
        }
    }
    
}

 
if (config.runsInWidget) {
  // create and show widget
    
   
    var listWidge = new ListWidget()
    
    listWidge.backgroundColor= Color.black()
    //.setPadding(top, leading, bottom, trailing)
    listWidge.setPadding(4, 4, 4, 4)
    
    var forumHeader = listWidge.addStack()
    forumHeader.layoutHorizontally()
    var forumHD = forumHeader.addText("Tumult Forum")
    forumHD.font = Font.semiboldRoundedSystemFont(12)
    forumHeader.topAlignContent()
    forumHD.textColor = Color.white()
    
    var fmwidth = parseInt(forumHeader.size.width/2)
    forumHeader.setPadding(2, 120, 0, 100)
   
    
    
  
    
    for (i = 0; i < widgetPostLimit ; i++) {
       
        //-- topic list item
        var jPosters =  jTopics[i]
        
        //-- retrieve last poster details from topic post item
        var postDetails = await parseDetails(jPosters)
        
        //--RETRIEVE & BUILD USER/POSTER DETAILS
        var imurl = postDetails["avatarImage"]
        var iurl = new Request(imurl)
        var imgz = await iurl.loadImage();
        
        imgz.cornerRadius = 25

        //-- create first stack container
        var topStack = listWidge.addStack()
        topStack.cornerRadius = 10
        topStack.layoutHorizontally()
        topStack.size.height= 100
        topStack.topAlignContent()
        topStack.backgroundColor = new Color("#1c1c1e")
        
        //-- create image stack container inside top stack
        var imageStack = topStack.addStack()
        imageStack.centerAlignContent()
         
        imageStack.cornerRadius = imageSize/2
        
      
        //-- add the image
        var wimg = imageStack.addImage(imgz)
        wimg.leftAlignImage()
        wimg.imageSize= new Size(imageSize,imageSize)
        
        
        //-- create topic title stack container inside top stack
        var topicTitleStack = topStack.addStack()
        
        topicTitleStack.backgroundColor  = new Color("#1c1c1e")
        
        topicTitleStack.centerAlignContent()
        topicTitleStack.setPadding(0, 4, 0, 0)
        topicTitleStack.width = 250
        
        //-- add the text
        var wtect1 = topicTitleStack.addText(postDetails.postTitle)
        
        wtect1.font = Font.semiboldRoundedSystemFont(16)
        wtect1.textColor = Color.blue()
        topStack.addSpacer()
        listWidge.addSpacer(3)
        
        //-- add link url to all stacks/ not sure which one user will click.
        topStack.url = postDetails.URLSlug
        imageStack.url = postDetails.URLSlug
        
       
        topicTitleStack.url = postDetails.URLSlug
        
        //-- add poster name for post
        var nameStack = topicTitleStack.addStack()
        
        topicTitleStack.layoutVertically()
        nameStack.bottomAlignContent()
        
        var wtect12 = topicTitleStack.addText(postDetails.posterUName)
         
        wtect12.font = Font.semiboldRoundedSystemFont(12)
        wtect12.textColor = Color.white()
  
  }
   
  
  Script.setWidget(listWidge)
  Script.complete()
} else {
    // MAKE TABLE FOR SHEET
    // make table
    let table = new UITable()
    
    // add header
    let row = new UITableRow()
    row.isHeader = true
    row.addText("Tumult Forum")
    table.addRow(row)
    
    // fill
    
    
    let posts = json.latest_posts
    
    
    for (i = 0; i < tablePostLimit; i++) {
        var jPosters =  jTopics[i]
        //-- retrieve last poster details from topic post item
        var postDetails = await parseDetails(jPosters)
        
        let row = new UITableRow()
        let thisSlug = postDetails.URLSlug
        row.onSelect = (idx) => {
            let item = jPosters[idx]
            
            Safari.open(thisSlug)
        }
        var imurl = postDetails["avatarImage"]
        var iurl = new Request(imurl)
        var imgz = await iurl.loadImage();
        
        //console.log(postDetails.posterUName)
        let title = postDetails.postTitle.toString()
        let subtitle = postDetails.posterUName
        let imageCell = row.addImageAtURL(imurl)
        let titleCell = row.addText(title, subtitle)
        imageCell.widthWeight = 20
        titleCell.widthWeight = 80
        row.height = 80
        row.cellSpacing = 10
        table.addRow(row)
}

  
  
//   
  if (config.runsWithSiri)
      Speech.speak(`. Here are 10 of the latest Posts`)
    
  table.present()
}
 

//--PARSE POSTER DETAILS
function parseDetails(jPosters){


  var item = jPosters.fancy_title
        var posterName = jPosters.last_poster_username
        var itemID = jPosters.id
        var itemPostCount = jPosters.posts_count
    
//-- ODD ERROR ,SOMETIME A USERS IMAGE CANNOT BE FOUND, SO we try catch
        try {
            var itemTitleUrlSlug =   (forumURL + "/t/" + jPosters.slug + "/" + itemID  + "/" + itemPostCount).toString()
            var fancyTitle = item.toString()
            var latestPosterImageID =  jPoster(jPosters.posters)
         
                    var userImage = jImage(latestPosterImageID).toString()
                   
                
          
           var imageURL = userImage.replace('{size}', 50);
           
         
         if (imageURL.indexOf('http')!=0) {
            imageURL = forumURL+imageURL
         }
        
            var userImage = jImage(latestPosterImageID).toString()
                   
                
          
           var imageURL = userImage.replace('{size}', 50);
           
         
         if (imageURL.indexOf('http')!=0) {
            imageURL = forumURL+imageURL
         }
         
            
        }
        catch(err) {
         
          var imageURL = "https://blog.tumult.com/wp-content/uploads/2015/03/hype-icon.jpg"
            
        }
        

	var itemTitleUrlSlug =   (forumURL + "/t/" + jPosters.slug + "/" + itemID  + "/" + itemPostCount).toString()  
	var fancyTitle = item.toString()
	var latestPosterImageID =  jPoster(jPosters.posters)
 
   

var theResults = {URLSlug: itemTitleUrlSlug,avatarImage:imageURL,postTitle : fancyTitle ,posterUName:posterName}

return theResults

}

file:

ForumMHv3.js.zip (2.6 KB)

1 Like

This is now updated to v3,


The code and a detailed Read Me, is now updated and on GitHub.

There are now three examples.
One for tumult and one for Scriptable’s forum and third bonus script for the Discourse forum

Updates:
•Added a try catch to the code for the images. There is an odd error that pops up every now and then when a new post is done, the posters image id/image cannot be found.

•fixed a bug which stopped avatar images being found if new single posts. github updated (05/11/20)
• Renamed the project on Github to reflect that the script is actually is versatile enough to load other Discourse powered forums with a small edit to the target url/json (14/03/23)
• Added a Discourse forum script example. (14/03/23)
• Change last post time to use Bumped_at time (14/03/23)

4 Likes