diff --git a/Resources/PostBuild.ps1 b/Resources/PostBuild.ps1
index 03fd9026..bba51d12 100644
--- a/Resources/PostBuild.ps1
+++ b/Resources/PostBuild.ps1
@@ -102,7 +102,7 @@ try{
     $lines = [IO.File]::ReadLines($file.FullName)
     $lines = $lines | ForEach-Object { $_.TrimStart() }
     $lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
-    $lines = $lines -Replace '(?<!\w)return(\s.*?)? if (.*?);', 'if ($2)return$1;'
+    $lines = $lines -Replace '(?<!\w)(return|throw)(\s.*?)? if (.*?);', 'if ($3)$1$2;'
     Rewrite-File $file $lines $imports
   }
   
diff --git a/Resources/Scripts/code.js b/Resources/Scripts/code.js
index 22a3a225..bbc69aff 100644
--- a/Resources/Scripts/code.js
+++ b/Resources/Scripts/code.js
@@ -95,6 +95,22 @@
     return result;
   };
   
+  //
+  // Function: Executes a function inside a try-catch to stop it from crashing everything.
+  //
+  const execSafe = function(func, fail){
+    try{
+      func();
+    }catch(err){
+      console.error(err);
+      
+      debugger;
+      $TD.crashDebug("Caught error in function "+func.name)
+      
+      fail && fail();
+    }
+  };
+  
   //
   // Function: Retrieves a property of an element with a specified class.
   //
@@ -113,15 +129,17 @@
   //
   // Block: Fix columns missing any identifiable attributes to allow individual styles.
   //
-  $(document).on("uiColumnRendered", function(e, data){
-    let icon = data.$column.find(".column-type-icon").first();
-    return if icon.length !== 1;
-    
-    let name = Array.prototype.find.call(icon[0].classList, cls => cls.startsWith("icon-"));
-    return if !name;
-    
-    data.$column.attr("data-td-icon", name);
-    data.column._tduck_icon = name;
+  execSafe(function setupColumnAttrIdentifiers(){
+    $(document).on("uiColumnRendered", function(e, data){
+      let icon = data.$column.find(".column-type-icon").first();
+      return if icon.length !== 1;
+      
+      let name = Array.prototype.find.call(icon[0].classList, cls => cls.startsWith("icon-"));
+      return if !name;
+      
+      data.$column.attr("data-td-icon", name);
+      data.column._tduck_icon = name;
+    });
   });
   
   //
@@ -139,17 +157,17 @@
     let recentTweets = new Set();
     let recentTweetTimer = null;
     
-    let resetRecentTweets = () => {
+    const resetRecentTweets = () => {
       recentTweetTimer = null;
       recentTweets.clear();
     };
     
-    let startRecentTweetTimer = () => {
+    const startRecentTweetTimer = () => {
       recentTweetTimer && window.clearTimeout(recentTweetTimer);
       recentTweetTimer = window.setTimeout(resetRecentTweets, 20000);
     };
     
-    let checkTweetCache = (set, id) => {
+    const checkTweetCache = (set, id) => {
       return true if set.has(id);
       
       if (set.size > 50){
@@ -160,7 +178,7 @@
       return false;
     };
     
-    let isSensitive = (tweet) => {
+    const isSensitive = (tweet) => {
       let main = tweet.getMainTweet && tweet.getMainTweet();
       return true if main && main.possiblySensitive; // TODO these don't show media badges when hiding sensitive media
       
@@ -173,7 +191,7 @@
       return false;
     };
     
-    let fixMedia = (html, media) => {
+    const fixMedia = (html, media) => {
       return html.find("a[data-media-entity-id='"+media.mediaId+"'], .media-item").first().removeClass("is-zoomable").css("background-image", 'url("'+media.small()+'")');
     };
     
@@ -291,11 +309,11 @@
   //
   // Function: Shows tweet detail, used in notification context menu.
   //
-  (function(){
-    return if !ensurePropertyExists(TD, "ui", "updates", "showDetailView");
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "showColumn");
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "getByApiid");
-    return if !ensurePropertyExists(TD, "controller", "clients", "getPreferredClient");
+  execSafe(function setupShowTweetDetail(){
+    throw 1 if !ensurePropertyExists(TD, "ui", "updates", "showDetailVieww");
+    throw 2 if !ensurePropertyExists(TD, "controller", "columnManager", "showColumn");
+    throw 3 if !ensurePropertyExists(TD, "controller", "columnManager", "getByApiid");
+    throw 4 if !ensurePropertyExists(TD, "controller", "clients", "getPreferredClient");
     
     const showTweetDetailInternal = function(column, chirp){
       TD.ui.updates.showDetailView(column, chirp, column.findChirp(chirp) || chirp);
@@ -338,12 +356,21 @@
         });
       }
     };
-  })();
+  }, function(){
+    window.TDGF_showTweetDetail = function(){
+      alert("error|This feature is not available due to an internal error.");
+    };
+  });
   
   //
   // Block: Hook into settings object to detect when the settings change, and update html attributes and notification layout.
   //
-  (function(){
+  execSafe(function hookTweetDeckSettings(){
+    throw 1 if !ensurePropertyExists(TD, "settings", "getFontSize");
+    throw 2 if !ensurePropertyExists(TD, "settings", "setFontSize");
+    throw 3 if !ensurePropertyExists(TD, "settings", "getTheme");
+    throw 4 if !ensurePropertyExists(TD, "settings", "setTheme");
+    
     const refreshSettings = function(){
       let fontSizeName = TD.settings.getFontSize();
       let themeName = TD.settings.getTheme();
@@ -374,7 +401,7 @@
     });
     
     onAppReady.push(refreshSettings);
-  })();
+  });
   
   //
   // Block: Fix OS name and add ID to the document for priority CSS selectors.
@@ -393,7 +420,9 @@
   //
   // Block: Enable popup notifications.
   //
-  if (ensurePropertyExists(TD, "controller", "notifications")){
+  execSafe(function hookDesktopNotifications(){
+    throw 1 if !ensurePropertyExists(TD, "controller", "notifications");
+    
     TD.controller.notifications.hasNotifications = function(){
       return true;
     };
@@ -401,18 +430,18 @@
     TD.controller.notifications.isPermissionGranted = function(){
       return true;
     };
-  }
-  
-  $.subscribe("/notifications/new", function(obj){
-    for(let index = obj.items.length-1; index >= 0; index--){
-      onNewTweet(obj.column, obj.items[index]);
-    }
+    
+    $.subscribe("/notifications/new", function(obj){
+      for(let index = obj.items.length-1; index >= 0; index--){
+        onNewTweet(obj.column, obj.items[index]);
+      }
+    });
   });
   
   //
   // Block: Add TweetDuck buttons to the settings menu.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function setupSettingsDropdown(){
     $$("[data-action='settings-menu']").click(function(){
       setTimeout(function(){
         let menu = $(".js-dropdown-content").children("ul").first();
@@ -437,7 +466,7 @@
   //
   // Block: Expand shortened links on hover or display tooltip.
   //
-  (function(){
+  execSafe(function setupLinkExpansionOrTooltip(){
     let prevMouseX = -1, prevMouseY = -1;
     let tooltipTimer, tooltipDisplayed;
     
@@ -484,51 +513,53 @@
         }
       }
     });
-  })();
+  });
   
   //
   // Block: Bypass t.co when clicking/dragging links and media.
   //
-  $(document.body).delegate("a[data-full-url]", "click auxclick", function(e){
-    if (e.button === 0 || e.button === 1){ // event.which seems to be borked in auxclick
-      $TD.openBrowser($(this).attr("data-full-url"));
-      e.preventDefault();
-    }
-  });
-  
-  $(document.body).delegate("a[data-full-url]", "dragstart", function(e){
-    let url = $(this).attr("data-full-url");
-    let data = e.originalEvent.dataTransfer;
+  execSafe(function setupShortenerBypass(){
+    $(document.body).delegate("a[data-full-url]", "click auxclick", function(e){
+      if (e.button === 0 || e.button === 1){ // event.which seems to be borked in auxclick
+        $TD.openBrowser($(this).attr("data-full-url"));
+        e.preventDefault();
+      }
+    });
     
-    data.clearData();
-    data.setData("text/uri-list", url);
-    data.setData("text/plain", url);
-    data.setData("text/html", `<a href="${url}">${url}</a>`);
-  });
-  
-  if (ensurePropertyExists(TD, "services", "TwitterMedia", "prototype", "fromMediaEntity")){
-    const prevFunc = TD.services.TwitterMedia.prototype.fromMediaEntity;
-    
-    TD.services.TwitterMedia.prototype.fromMediaEntity = function(){
-      let obj = prevFunc.apply(this, arguments);
-      let e = arguments[0];
+    $(document.body).delegate("a[data-full-url]", "dragstart", function(e){
+      let url = $(this).attr("data-full-url");
+      let data = e.originalEvent.dataTransfer;
       
-      if (e.expanded_url){
-        if (obj.url === obj.shortUrl){
-          obj.shortUrl = e.expanded_url;
+      data.clearData();
+      data.setData("text/uri-list", url);
+      data.setData("text/plain", url);
+      data.setData("text/html", `<a href="${url}">${url}</a>`);
+    });
+    
+    if (ensurePropertyExists(TD, "services", "TwitterMedia", "prototype", "fromMediaEntity")){
+      const prevFunc = TD.services.TwitterMedia.prototype.fromMediaEntity;
+      
+      TD.services.TwitterMedia.prototype.fromMediaEntity = function(){
+        let obj = prevFunc.apply(this, arguments);
+        let e = arguments[0];
+        
+        if (e.expanded_url){
+          if (obj.url === obj.shortUrl){
+            obj.shortUrl = e.expanded_url;
+          }
+          
+          obj.url = e.expanded_url;
         }
         
-        obj.url = e.expanded_url;
-      }
-      
-      return obj;
-    };
-  }
+        return obj;
+      };
+    }
+  });
   
   //
   // Block: Bypass t.co in user profiles and setup a top tier account bamboozle scheme.
   //
-  (function(){
+  execSafe(function setupAccountLoadHook(){
     const realDisplayName = "TweetDuck";
     const realAvatar = "https://ton.twimg.com/tduck/avatar";
     const accountId = "957608948189880320";
@@ -585,31 +616,33 @@
         }, onError);
       };
     }
-  })();
+  });
   
   //
   // Block: Include additional information in context menus.
   //
-  $(document.body).delegate("a", "contextmenu", function(){
-    let me = $(this)[0];
-    
-    if (me.classList.contains("js-media-image-link") && highlightedTweetObj){
-      let tweet = highlightedTweetObj.hasMedia() ? highlightedTweetObj : highlightedTweetObj.quotedTweet;
-      let media = tweet.getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
+  execSafe(function setupContextMenuInfo(){
+    $(document.body).delegate("a", "contextmenu", function(){
+      let me = $(this)[0];
       
-      if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
-        $TD.setRightClickedLink("video", media.chooseVideoVariant().url);
+      if (me.classList.contains("js-media-image-link") && highlightedTweetObj){
+        let tweet = highlightedTweetObj.hasMedia() ? highlightedTweetObj : highlightedTweetObj.quotedTweet;
+        let media = tweet.getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
+        
+        if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
+          $TD.setRightClickedLink("video", media.chooseVideoVariant().url);
+        }
+        else{
+          $TD.setRightClickedLink("image", media.large());
+        }
+      }
+      else if (me.classList.contains("js-gif-play")){
+        $TD.setRightClickedLink("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
       }
       else{
-        $TD.setRightClickedLink("image", media.large());
+        $TD.setRightClickedLink("link", me.getAttribute("data-full-url"));
       }
-    }
-    else if (me.classList.contains("js-gif-play")){
-      $TD.setRightClickedLink("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
-    }
-    else{
-      $TD.setRightClickedLink("link", me.getAttribute("data-full-url"));
-    }
+    });
   });
   
   //
@@ -646,9 +679,9 @@
   //
   // Block: Update highlighted column and tweet for context menu and other functionality.
   //
-  (function(){
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "get");
-    return if !ensurePropertyExists(TD, "services", "ChirpBase", "TWEET");
+  execSafe(function setupHighlightedColumn(){
+    throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "get");
+    throw 2 if !ensurePropertyExists(TD, "services", "ChirpBase", "TWEET");
     
     const updateHighlightedColumn = function(ele){
       highlightedColumnEle = ele;
@@ -705,12 +738,12 @@
         updateHighlightedTweet(null, null);
       }
     });
-  })();
+  });
   
   //
   // Block: Screenshot tweet to clipboard.
   //
-  (function(){
+  execSafe(function setupTweetScreenshot(){
     window.TDGF_triggerScreenshot = function(){
       return if !highlightedTweetObj || !highlightedColumnObj;
       
@@ -764,12 +797,16 @@
       
       $TD.screenshotTweet(html[0].outerHTML, columnWidth);
     };
-  })();
+  }, function(){
+    window.TDGF_triggerScreenshot = function(){
+      alert("error|This feature is not available due to an internal error.");
+    };
+  });
   
   //
   // Block: Paste images when tweeting.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function supportImagePaste(){
     const uploader = $._data(document, "events")["uiComposeAddImageClick"][0].handler.context;
     
     app.delegate(".js-compose-text,.js-reply-tweetbox,.td-detect-image-paste", "paste", function(e){
@@ -807,7 +844,7 @@
   //
   // Block: Support for extra mouse buttons.
   //
-  (function(){
+  execSafe(function supportExtraMouseButtons(){
     const tryClickSelector = function(selector, parent){
       return $(selector, parent).click().length;
     };
@@ -847,12 +884,12 @@
         }
       }
     };
-  })();
+  });
   
   //
   // Block: Allow drag & drop behavior for dropping links on columns to open their detail view.
   //
-  (function(){
+  execSafe(function supportDragDropOverColumns(){
     const tweetRegex = /^https?:\/\/twitter\.com\/[A-Za-z0-9_]+\/status\/(\d+)\/?\??/;
     const selector = "section.js-column";
     
@@ -895,13 +932,13 @@
         app.undelegate(selector, events);
       }
     };
-  })();
+  });
   
   //
   // Block: Fix scheduled tweets not showing up sometimes.
   //
-  (function(){
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
+  execSafe(function fixScheduledTweets(){
+    throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
     
     $(document).on("dataTweetSent", function(e, data){
       if (data.response.state && data.response.state === "scheduled"){
@@ -914,13 +951,13 @@
         }
       }
     });
-  })();
+  });
   
   //
   // Block: Hold Shift to restore cleared column.
   //
-  (function(){
-    return if !ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
+  execSafe(function supportShiftToClearColumn(){
+    throw 1 if !ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
     
     let holdingShift = false;
     
@@ -954,12 +991,12 @@
         return true;
       }
     });
-  })();
+  });
   
   //
   // Block: Refocus the textbox after switching accounts.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function setupAccountSwitchRefocus(){
     const composeInput = $$(".js-compose-text", ".js-docked-compose");
     
     const refocusInput = function(){
@@ -974,74 +1011,76 @@
   //
   // Block: Make middle click on tweet reply icon open the compose drawer, retweet icon trigger a quote, and favorite icon open a 'Like from accounts...' modal.
   //
-  app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
-    return if e.which !== 2;
-    
-    let column = TD.controller.columnManager.get($(this).closest("section.js-column").attr("data-column"));
-    return if !column;
-    
-    let ele = $(this).closest("article");
-    let tweet = column.findChirp(ele.attr("data-tweet-id")) || column.findChirp(ele.attr("data-key"));
-    return if !tweet;
-    
-    switch($(this).attr("rel")){
-      case "reply":
-        let main = tweet.getMainTweet();
-        
-        $(document).trigger("uiDockedComposeTweet", {
-          type: "reply",
-          from: [ tweet.account.getKey() ],
-          inReplyTo: {
-            id: tweet.id,
-            htmlText: main.htmlText,
-            user: {
-              screenName: main.user.screenName,
-              name: main.user.name,
-              profileImageURL: main.user.profileImageURL
-            }
-          },
-          mentions: tweet.getReplyUsers(),
-          element: ele
-        });
-        
-        break;
-        
-      case "favorite":
-        $(document).trigger("uiShowFavoriteFromOptions", { tweet });
-        break;
-        
-      case "retweet":
-        TD.controller.stats.quoteTweet();
-        
-        $(document).trigger("uiComposeTweet", {
-          type: "tweet",
-          from: [ tweet.account.getKey() ],
-          quotedTweet: tweet.getMainTweet(),
-          element: ele // triggers reply-account plugin
-        });
-        
-        break;
+  execSafe(function supportMiddleClickTweetActions(){
+    app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
+      return if e.which !== 2;
       
-      default:
-        return;
-    }
-    
-    e.preventDefault();
-    e.stopPropagation();
-    e.stopImmediatePropagation();
+      let column = TD.controller.columnManager.get($(this).closest("section.js-column").attr("data-column"));
+      return if !column;
+      
+      let ele = $(this).closest("article");
+      let tweet = column.findChirp(ele.attr("data-tweet-id")) || column.findChirp(ele.attr("data-key"));
+      return if !tweet;
+      
+      switch($(this).attr("rel")){
+        case "reply":
+          let main = tweet.getMainTweet();
+          
+          $(document).trigger("uiDockedComposeTweet", {
+            type: "reply",
+            from: [ tweet.account.getKey() ],
+            inReplyTo: {
+              id: tweet.id,
+              htmlText: main.htmlText,
+              user: {
+                screenName: main.user.screenName,
+                name: main.user.name,
+                profileImageURL: main.user.profileImageURL
+              }
+            },
+            mentions: tweet.getReplyUsers(),
+            element: ele
+          });
+          
+          break;
+          
+        case "favorite":
+          $(document).trigger("uiShowFavoriteFromOptions", { tweet });
+          break;
+          
+        case "retweet":
+          TD.controller.stats.quoteTweet();
+          
+          $(document).trigger("uiComposeTweet", {
+            type: "tweet",
+            from: [ tweet.account.getKey() ],
+            quotedTweet: tweet.getMainTweet(),
+            element: ele // triggers reply-account plugin
+          });
+          
+          break;
+        
+        default:
+          return;
+      }
+      
+      e.preventDefault();
+      e.stopPropagation();
+      e.stopImmediatePropagation();
+    });
   });
   
   //
   // Block: Work around clipboard HTML formatting.
   //
-  $(document).on("copy", function(e){
+  document.addEventListener("copy", function(){
     window.setTimeout($TD.fixClipboard, 0);
   });
   
   //
   // Block: Inject custom CSS and layout into the page.
   //
-  (function(){
+  execSafe(function setupStyleInjection(){
     const createStyle = function(id, styles){
       let ele = document.createElement("style");
       ele.id = id;
@@ -1062,7 +1101,7 @@
         createStyle("tweetduck-custom-css", styles);
       }
     };
-  })();
+  });
   
   //
   // Block: Setup global function to inject custom HTML into mustache templates.
@@ -1115,7 +1154,7 @@
   //
   // Block: Setup video player hooks.
   //
-  (function(){
+  execSafe(function setupVideoPlayer(){
     window.TDGF_playVideo = function(url, username){
       $('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
         $TD.playVideo(null, null);
@@ -1132,11 +1171,11 @@
       let parent = obj.closest(".js-tweet").first();
       let link = (parent.hasClass("tweet-detail") ? parent.find("a[rel='url']") : parent.find("time").first().children("a")).first();
       return link.attr("href");
-    }
+    };
     
     const getUsername = function(tweet){
       return tweet && (tweet.quotedTweet || tweet).getMainUser().screenName;
-    }
+    };
     
     app.delegate(".js-gif-play", {
       click: function(e){
@@ -1170,9 +1209,9 @@
     
     TD.mustaches["media/native_video.mustache"] = '<div class="js-media-gif-container media-item nbfc is-video" style="background-image:url({{imageSrc}})"><video class="js-media-gif media-item-gif full-width block {{#isPossiblySensitive}}is-invisible{{/isPossiblySensitive}}" loop src="{{videoUrl}}"></video><a class="js-gif-play pin-all is-actionable">{{> media/video_overlay}}</a></div>';
     
-    return if !ensurePropertyExists(TD, "components", "MediaGallery", "prototype", "_loadTweet");
-    return if !ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer");
-    return if !ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused");
+    throw 1 if !ensurePropertyExists(TD, "components", "MediaGallery", "prototype", "_loadTweet");
+    throw 2 if !ensurePropertyExists(TD, "components", "BaseModal", "prototype", "setAndShowContainer");
+    throw 3 if !ensurePropertyExists(TD, "ui", "Column", "prototype", "playGifIfNotManuallyPaused");
     
     let cancelModal = false;
     
@@ -1193,7 +1232,11 @@
     });
     
     TD.ui.Column.prototype.playGifIfNotManuallyPaused = function(){};
-  })();
+  }, function(){
+    window.TDGF_playVideo = function(){
+      alert("error|This feature is not available due to an internal error.");
+    };
+  });
   
   //
   // Block: Fix youtu.be previews not showing up for https links.
@@ -1214,7 +1257,7 @@
   //
   // Block: Add a pin icon to make tweet compose drawer stay open.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function setupStayOpenPin(){
     let ele = $(`
 <svg id="td-compose-drawer-pin" viewBox="0 0 24 24" class="icon js-show-tip" data-original-title="Stay open" data-tooltip-position="left">
  <path d="M9.884,16.959l3.272,0.001l-0.82,4.568l-1.635,0l-0.817,-4.569Z"/>
@@ -1242,9 +1285,9 @@
   //
   // Block: Make temporary search column appear as the first one and clear the input box.
   //
-  (function(){
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "_columnOrder");
-    return if !ensurePropertyExists(TD, "controller", "columnManager", "move");
+  execSafe(function setupSearchColumnHook(){
+    throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "_columnOrder");
+    throw 2 if !ensurePropertyExists(TD, "controller", "columnManager", "move");
     
     $(document).on("uiSearchNoTemporaryColumn", function(e, data){
       if (data.query && data.searchScope !== "users" && !data.columnKey){
@@ -1266,23 +1309,27 @@
         }
       }
     });
-  })();
+  });
   
   //
   // Block: Setup global function to add a search column with the specified query.
   //
-  onAppReady.push(function(){
+  onAppReady.push(() => execSafe(function setupSearchFunction(){
     let context = $._data(document, "events")["uiSearchInputSubmit"][0].handler.context;
     
     window.TDGF_performSearch = function(query){
       context.performSearch({ query, tweetduck: true });
     };
-  });
+  }, function(){
+    window.TDGF_performSearch = function(){
+      alert("error|This feature is not available due to an internal error.");
+    };
+  }));
   
   //
   // Block: Reorder search results to move accounts above hashtags.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function reorderSearchResults(){
     let container = $(".js-search-in-popover");
     let hashtags = $$(".js-typeahead-topic-list", container);
     
@@ -1293,7 +1340,7 @@
   //
   // Block: Make submitting search queries while holding Ctrl or middle-clicking the search icon open the search externally.
   //
-  onAppReady.push(function(){
+  onAppReady.push(function setupSearchTriggerHook(){
     const openSearchExternally = function(event, input){
       $TD.openBrowser("https://twitter.com/search/?q="+encodeURIComponent(input.val() || ""));
       event.preventDefault();
@@ -1332,9 +1379,14 @@
   //
   // Block: Setup global function to refresh all columns.
   //
-  window.TDGF_reloadColumns = function(){
-    Object.values(TD.controller.columnManager.getAll()).forEach(column => column.reloadTweets());
-  };
+  if (ensurePropertyExists(TD, "controller", "columnManager", "getAll")){
+    window.TDGF_reloadColumns = function(){
+      Object.values(TD.controller.columnManager.getAll()).forEach(column => column.reloadTweets());
+    };
+  }
+  else{
+    window.TDGF_reloadColumns = function(){};
+  }
   
   //
   // Block: Allow applying ROT13 to input selection.
@@ -1356,7 +1408,7 @@
   //
   // Block: Revert Like/Follow dialogs being closed after clicking an action.
   //
-  (function(){
+  execSafe(function setupLikeFollowDialogRevert(){
     const prevSetTimeout = window.setTimeout;
     
     const overrideState = function(){
@@ -1401,7 +1453,7 @@
         };
       });
     });
-  })();
+  });
   
   //
   // Block: Fix DM reply input box not getting focused after opening a conversation.
@@ -1466,7 +1518,7 @@
   // Block: Detect and notify about connection issues.
   //
   (function(){
-    let onConnectionError = function(){
+    const onConnectionError = function(){
       return if $("#tweetduck-conn-issues").length;
       
       let ele = $(`
@@ -1487,7 +1539,7 @@
       });
     };
     
-    let onConnectionFine = function(){
+    const onConnectionFine = function(){
       let ele = $("#tweetduck-conn-issues");
       
       ele.fadeOut(200, function(){
@@ -1558,7 +1610,9 @@
       }
     };
     
-    if (ensurePropertyExists(TD, "controller", "columnManager", "getAll")){
+    execSafe(function showMissedNotifications(){
+      throw 1 if !ensurePropertyExists(TD, "controller", "columnManager", "getAll");
+      
       $(document).one("dataColumnsLoaded", function(){
         let columns = Object.values(TD.controller.columnManager.getAll());
         let remaining = columns.length;
@@ -1571,14 +1625,16 @@
           });
         }
       });
-    }
+    });
   }
   
   //
   // Block: Disable default TweetDeck update notification.
   //
-  $(document).on("uiSuggestRefreshToggle", function(e){
-    e.stopImmediatePropagation();
+  execSafe(function disableTweetDeckUpdates(){
+    $(document).on("uiSuggestRefreshToggle", function(e){
+      e.stopImmediatePropagation();
+    });
   });
   
   //
@@ -1593,7 +1649,7 @@
     TD.metrics.send = noop;
   }
   
-  onAppReady.push(function(){
+  onAppReady.push(function disableMetrics(){
     let data = $._data(window);
     delete data.events["metric"];
     delete data.events["metricsFlush"];
@@ -1603,7 +1659,7 @@
   // Block: Register the TD.ready event, finish initialization, and load plugins.
   //
   $(document).one("TD.ready", function(){
-    onAppReady.forEach(func => func());
+    onAppReady.forEach(func => execSafe(func));
     onAppReady = null;
     
     delete window.TD_SESSION;