Spotify Webview on BTT Mobile ?

Hallo @Andreas_Hegenberg,

I have here a nice Webview for Spotify with clickable processbar ect. (thx ChatGPT !),
which works fine on Mac, but when try the same on BTT Mobile I got errors...

Is the webview & scripts in that case actually "run" on the BTT Mobile "side" and not on the Mac (by BTT) ?


..
here the Spotify Floating menu / webview:

[
  {
    "BTTActionCategory" : 0,
    "BTTLastUpdatedAt" : 1749592929.533479,
    "BTTTriggerType" : 767,
    "BTTTriggerTypeDescriptionReadOnly" : "Floating Menu",
    "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
    "BTTUUID" : "00960D90-33F1-4DD5-8C29-1B50FDDE8E35",
    "BTTPredefinedActionType" : 366,
    "BTTPredefinedActionName" : "Empty Placeholder",
    "BTTAdditionalConfiguration" : "Floating Menu: Text Editor",
    "BTTEnabled" : 1,
    "BTTOrder" : 2,
    "BTTTriggerName" : "Floating Menu: WebView-Spotify",
    "BTTMenuItems" : [
      {
        "BTTActionCategory" : 0,
        "BTTLastUpdatedAt" : 1749409743.912863,
        "BTTTriggerType" : 773,
        "BTTTriggerTypeDescription" : "Standard Item",
        "BTTTriggerParentUUID" : "00960D90-33F1-4DD5-8C29-1B50FDDE8E35",
        "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
        "BTTUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
        "BTTPredefinedActionType" : 366,
        "BTTPredefinedActionName" : "Empty Placeholder",
        "BTTAdditionalConfiguration" : "Menu Item: Titel",
        "BTTEnabled" : 1,
        "BTTOrder" : 0,
        "BTTTriggerName" : "Menu Item: Titel",
        "BTTMenuItemActions" : [
          {
            "BTTActionCategory" : 0,
            "BTTLastUpdatedAt" : 1749403887.6648002,
            "BTTTriggerParentUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
            "BTTIsPureAction" : true,
            "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
            "BTTUUID" : "52F42E4C-A7D6-49DB-A18F-7EA2ACEB4C8B",
            "BTTPredefinedActionType" : 334,
            "BTTPredefinedActionName" : "END If Condition",
            "BTTEnabled" : 1,
            "BTTOrder" : 5,
            "BTTMenuAvailability" : 0,
            "BTTMenuName" : "52F42E4C-A7D6-49DB-A18F-7EA2ACEB4C8B"
          },
          {
            "BTTActionCategory" : 0,
            "BTTLastUpdatedAt" : 1749403057.6709042,
            "BTTTriggerParentUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
            "BTTIsPureAction" : true,
            "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
            "BTTUUID" : "083A1C38-19EC-4368-A4F9-00FC4F9BF73A",
            "BTTPredefinedActionType" : 330,
            "BTTPredefinedActionName" : "If Condition",
            "BTTIfConditionFormat" : "fingers_touching_trackpad >= 0 AND left_mouse_down == 0",
            "BTTIfConditionData" : "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGvEB8LDBMZISssLjU5Pj9CRkpNT1JYXWFma29yc3Z3fH+BVSRudWxs0w0ODxAREl8QF05TQ29tcG91bmRQcmVkaWNhdGVUeXBlXxAPTlNTdWJwcmVkaWNhdGVzViRjbGFzcxABgAKAHtIUDxUYWk5TLm9iamVjdHOiFheAA4AUgB3UDxobHB0eHyBfEBFOU1JpZ2h0RXhwcmVzc2lvbl8QEE5TTGVmdEV4cHJlc3Npb25fEBNOU1ByZWRpY2F0ZU9wZXJhdG9ygBOADoAEgBHVIiMkJQ8mJygpKllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzgAaABRADgAiADVx2YWx1ZUZvcktleTrSJA8QLYAH0i8wMTJaJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TU2VsZkV4cHJlc3Npb26jMTM0XE5TRXhwcmVzc2lvblhOU09iamVjdNIUDzY4oTeACYAM0w8kOjs8PVlOU0tleVBhdGiACxAKgApfEBlmaW5nZXJzX3RvdWNoaW5nX3RyYWNrcGFk0i8wQEFfEBxOU0tleVBhdGhTcGVjaWZpZXJFeHByZXNzaW9uo0AzNNIvMENEXk5TTXV0YWJsZUFycmF5o0NFNFdOU0FycmF50i8wR0hfEBNOU0tleVBhdGhFeHByZXNzaW9upEdJMzRfEBROU0Z1bmN0aW9uRXhwcmVzc2lvbtNLJA9MTU5fEA9OU0NvbnN0YW50VmFsdWWADxAAgBDSLzBQUV8QGU5TQ29uc3RhbnRWYWx1ZUV4cHJlc3Npb26jUDM01Q9TVFVWV00oTShaTlNNb2RpZmllcllOU1ZhcmlhbnRZTlNPcHRpb25zXk5TT3BlcmF0b3JUeXBlgBLSLzBZWl8QHU5TQ29tcGFyaXNvblByZWRpY2F0ZU9wZXJhdG9yo1tcNF8QHU5TQ29tcGFyaXNvblByZWRpY2F0ZU9wZXJhdG9yXxATTlNQcmVkaWNhdGVPcGVyYXRvctIvMF5fXxAVTlNDb21wYXJpc29uUHJlZGljYXRlo15gNFtOU1ByZWRpY2F0ZdQPGhscHWNkZYATgBmAFYAb1SIjJCUPJicoaSqABoAFgBaADdIUD2w4oW2AF4AM0w8kOjs8cYALgBhfEA9sZWZ0X21vdXNlX2Rvd27TSyQPdE1OgBqAEAjVD1N4VVZ5TXZNe1hOU05lZ2F0ZYAcCBAE0i8wfX5fEBtOU0VxdWFsaXR5UHJlZGljYXRlT3BlcmF0b3KjfVw00i8wRYCiRTTSLzCCg18QE05TQ29tcG91bmRQcmVkaWNhdGWjgmA0AAgAEQAaACQAKQAyADcASQBMAFEAUwB1AHsAggCcAK4AtQC3ALkAuwDAAMsAzgDQANIA1ADdAPEBBAEaARwBHgEgASIBLQE3AUYBWQFlAWcBaQFrAW0BbwF8AYEBgwGIAZMBnAGvAbMBwAHJAc4B0AHSAdQB2wHlAecB6QHrAgcCDAIrAi8CNAJDAkcCTwJUAmoCbwKGAo0CnwKhAqMCpQKqAsYCygLVAuAC6gL0AwMDBQMKAyoDLgNOA2QDaQOBA4UDkQOaA5wDngOgA6IDrQOvA7EDswO1A7oDvAO+A8ADxwPJA8sD3QPkA+YD6APpA_QD_QP_BAAEAgQHBCUEKQQuBDEENgRMAAAAAAAAAgEAAAAAAAAAhAAAAAAAAAAAAAAAAAAABFA=",
            "BTTEnabled" : 1,
            "BTTOrder" : 1,
            "BTTMenuAvailability" : 0,
            "BTTMenuName" : "083A1C38-19EC-4368-A4F9-00FC4F9BF73A"
          },
          {
            "BTTActionCategory" : 0,
            "BTTLastUpdatedAt" : 1749403887.6648211,
            "BTTTriggerParentUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
            "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
            "BTTUUID" : "49826C3D-C95B-48EE-9638-EF9E1D64E940",
            "BTTPredefinedActionType" : 387,
            "BTTPredefinedActionName" : "Hide Floating Menu",
            "BTTAdditionalActionData" : {
              "BTTMenuActionMenuID" : "WebView-Spotify"
            },
            "BTTEnabled" : 0,
            "BTTOrder" : 4,
            "BTTMenuConfig" : {

            },
            "BTTMenuAvailability" : 0,
            "BTTMenuName" : "1AEA4003-A5DF-430C-BCB7-57E17689A002"
          },
          {
            "BTTActionCategory" : 0,
            "BTTLastUpdatedAt" : 1749403887.664844,
            "BTTTriggerParentUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
            "BTTIsPureAction" : true,
            "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
            "BTTUUID" : "7E349544-455D-44AA-AF72-85FB4ED2F51F",
            "BTTPredefinedActionType" : 333,
            "BTTPredefinedActionName" : "Else",
            "BTTEnabled" : 1,
            "BTTOrder" : 3,
            "BTTMenuAvailability" : 0,
            "BTTMenuName" : "7E349544-455D-44AA-AF72-85FB4ED2F51F"
          },
          {
            "BTTActionCategory" : 0,
            "BTTLastUpdatedAt" : 1749591826.7265711,
            "BTTTriggerParentUUID" : "CA6B1904-B0F8-4CDD-A831-58BBE253A0CB",
            "BTTIsPureAction" : true,
            "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
            "BTTUUID" : "A5D95FA3-E90E-41F4-B499-1F5AC7FC7F16",
            "BTTPredefinedActionType" : 490,
            "BTTPredefinedActionName" : "Comment (Does Nothing Else)",
            "BTTGenericActionConfig" : "⚠️ caution: deactivate item does not work !\nIf else endif workaround",
            "BTTEnabled" : 1,
            "BTTOrder" : 0,
            "BTTMenuAvailability" : 0,
            "BTTMenuName" : "A5D95FA3-E90E-41F4-B499-1F5AC7FC7F16"
          }
        ],
        "BTTMenuConfig" : {
          "BTTMenuHoverStartAnimationDuration" : 0.14999999999999999,
          "BTTMenuItemBackgroundColorHoverDark" : "90.000, 90.000, 180.000, 166.991",
          "BTTMenuItemIconColor1" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuItemBorderColorDark" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuItemBackgroundColor" : "28.000000, 185.000000, 85.000000, 255.000000",
          "BTTMenuCategoryItemVisibility" : 0,
          "BTTMenuItemBackgroundType" : 4,
          "BTTMenuItemMaxHeight" : 30,
          "BTTMenuCategoryMenuVisibility" : 0,
          "BTTMenuHoverEndAnimationDuration" : 0.14999999999999999,
          "BTTMenuItemMaxWidth" : 520,
          "BTTMenuCategoryItemIcon" : 0,
          "BTTMenuItemBorderWidth" : 0,
          "BTTMenuCategoryShadow" : 0,
          "BTTMenuCategoryItemBehavior" : 0,
          "BTTMenuCategoryOnlyShowIf" : 0,
          "BTTMenuItemCornerRadius" : 5,
          "BTTMenuCategoryModifiers" : 0,
          "BTTMenuItemBorderColorHover" : "55.000000, 90.000000, 127.000000, 255.000000",
          "BTTMenuCategoryItemSpacing" : 0,
          "BTTLastChangeUUID" : "C7BC039B-C1DB-4795-A7CE-A987A7A79DBF",
          "BTTMenuCategoryMenuOpacity" : 0,
          "BTTMenuItemBorderColor" : "55.000000, 90.000000, 127.000000, 255.000000",
          "BTTMenuCategorySize" : 0,
          "BTTMenuItemMinHeight" : 30,
          "BTTMenuItemBackgroundColorDark" : "108.442, 96.000, 190.435, 166.991",
          "BTTMenuItemVisibleWhileActive" : 1,
          "BTTMenuElementIdentifier" : "Titel",
          "BTTMenuItemVisibleWhileInactive" : 1,
          "BTTMenuItemMinWidth" : 520,
          "BTTMenuItemBackgroundTypeDark" : 4,
          "BTTMenuAttributedText" : "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fnil\\fcharset0 SFPro-Regular;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}\n{\\*\\expandedcolortbl;;\\cspthree\\c0\\c0\\c0;}\n\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs28 \\cf2 Spotify}",
          "BTTMenuCategorySpacing" : 0,
          "BTTMenuItemBorderColorHoverDark" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuAppearanceStyle" : 0,
          "BTTMenuItemBackgroundColorHover" : "28.000000, 185.000000, 85.000000, 255.000000",
          "BTTMenuAlwaysUseLightMode" : 1,
          "BTTMenuCategoryBackground" : 1,
          "BTTMenuCategoryItemSizing" : 0,
          "BTTMenuItemSelectedTab" : 0,
          "BTTMenuCategoryResizeOnHover" : 0,
          "BTTMenuCategoryBorder" : 0,
          "BTTMenuUseStyleForSubmenu" : 1,
          "BTTMenuCategoryZIndex" : 0,
          "BTTMenuCategoryPosition" : 0,
          "BTTMenuAttributedTextDark" : "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\pardirnatural\\partightenfactor0\n\n\\f0\\fs24 \\cf0 Multi Selection Dummy Text - You can change the formatting for multiple items at the same time, but not the text.}"
        },
        "BTTMenuAvailability" : 0,
        "BTTMenuName" : "Titel",
        "BTTGestureNotes" : "Standard Item"
      },
      {
        "BTTActionCategory" : 0,
        "BTTLastUpdatedAt" : 1749405518.1191061,
        "BTTTriggerType" : 778,
        "BTTTriggerTypeDescriptionReadOnly" : "Web View \/ HTML Item",
        "BTTTriggerTypeDescription" : "Standard Item",
        "BTTTriggerParentUUID" : "00960D90-33F1-4DD5-8C29-1B50FDDE8E35",
        "BTTTriggerClass" : "BTTTriggerTypeFloatingMenu",
        "BTTUUID" : "F8B1F9BB-69D2-4049-A49B-B255A32BAB30",
        "BTTEnabled" : 1,
        "BTTOrder" : 2,
        "BTTTriggerName" : "Webview Menu Item: WebView-Spotify-item",
        "BTTMenuConfig" : {
          "BTTMenuItemBackgroundColorHoverDark" : "90.000, 90.000, 180.000, 166.991",
          "BTTMenuCategoryItemPositioning" : 0,
          "BTTMenuItemBorderColorDark" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuItemIconColor1" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuItemDisplayOrder" : 0,
          "BTTMenuItemBackgroundColor" : "0.000, 0.000, 0.000, 255.000",
          "BTTMenuCategoryItemVisibility" : 0,
          "BTTMenuItemBackgroundType" : 0,
          "BTTMenuItemFocused" : 1,
          "BTTMenuItemMaxHeight" : 520,
          "BTTMenuHoverEndAnimationDuration" : 0.14999999999999999,
          "BTTMenuCategoryMenuVisibility" : 0,
          "BTTMenuItemMaxWidth" : 520,
          "BTTMenuCategoryItemIcon" : 0,
          "BTTMenuItemBorderWidth" : 0,
          "BTTMenuCategoryShadow" : 0,
          "BTTMenuCategoryItemBehavior" : 0,
          "BTTMenuCategoryOnlyShowIf" : 0,
          "BTTMenuItemCornerRadius" : 5,
          "BTTMenuCategoryModifiers" : 0,
          "BTTMenuCategoryItemSpacing" : 0,
          "BTTMenuItemBorderColorHover" : "192.288, 192.292, 192.290, 255.000",
          "BTTLastChangeUUID" : "EB5BF31C-A01F-46DD-8C40-1FE5B959B744",
          "BTTMenuCategoryMenuOpacity" : 0,
          "BTTMenuItemBorderColor" : "94.492, 94.494, 94.493, 255.000",
          "BTTMenuItemMinHeight" : 520,
          "BTTMenuItemWebViewFocusTextFieldWithID" : "focusTextArea",
          "BTTMenuCategorySize" : 0,
          "BTTMenuItemBackgroundColorDark" : "108.442, 96.000, 190.435, 166.991",
          "BTTMenuItemVisibleWhileActive" : 1,
          "BTTMenuElementIdentifier" : "WebView-Spotify-item",
          "BTTMenuItemVisibleWhileInactive" : 1,
          "BTTMenuItemMinWidth" : 520,
          "BTTMenuItemBackgroundTypeDark" : 4,
          "BTTMenuAttributedText" : "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fnil\\fcharset0 HelveticaNeue;}\n{\\colortbl;\\red255\\green255\\blue255;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c100000\\c100000\\c100000;}\n\\deftab720\n\\pard\\pardeftab720\\qc\\partightenfactor0\n\n\\f0\\fs44 \\cf2 \\expnd0\\expndtw0\\kerning0\n.}",
          "BTTMenuItemText" : "<html>\n  <head>\n    <link\n      href=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@5.3.0\/dist\/css\/bootstrap.min.css\"\n      rel=\"stylesheet\"\n    \/>\n    <link\n      href=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap-icons@1.10.5\/font\/bootstrap-icons.css\"\n      rel=\"stylesheet\"\n    \/>\n    <style>\n      body {\n        background-color: #111;\n        color: #fff;\n        font-family: \"San Francisco\", -apple-system, BlinkMacSystemFont, sans-serif;\n        padding: 20px;\n        overflow: hidden;\n        position: relative;\n        text-align: center;\n      }\n\n      #spotifyInfo img {\n        max-width: 60%;\n        border-radius: 12px;\n        box-shadow: 0 0 15px rgba(0, 0, 0, 0.6);\n        margin-bottom: 15px;\n      }\n\n      .scroll-text {\n        display: inline-block;\n        white-space: nowrap;\n        overflow: hidden;\n        width: 90%;\n      }\n\n      .scroll-text.scroll {\n        animation: scroll 10s linear infinite;\n      }\n\n      @keyframes scroll {\n        0% {\n          transform: translateX(100%);\n        }\n        100% {\n          transform: translateX(-100%);\n        }\n      }\n\n      h1, h2 {\n        margin: 0;\n        padding: 0;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n\n      h1 {\n        font-size: 1.2rem;\n        margin-bottom: 5px;\n      }\n\n      h2 {\n        font-size: 1rem;\n        font-weight: 300;\n        color: #ccc;\n        margin-bottom: 10px;\n      }\n\n      .error {\n        color: #ff6666;\n        font-size: 0.9rem;\n      }\n\n      .controls {\n        margin-top: 15px;\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        width: 100%;\n        gap: 15px;\n      }\n\n      .btn-group-fixed {\n        display: flex;\n        gap: 8px;\n      }\n\n      .btn {\n        font-size: 1.2rem;\n        width: 50px;\n        height: 40px;\n        border-radius: 0;\n        border: 1px solid #555;\n        background-color: #222;\n        color: #fff;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        transition: all 0.2s ease-in-out;\n      }\n\n      .btn:hover,\n      .btn.active {\n        background-color: #1DB954;\n        color: #fff;\n        border-color: #1DB954;\n      }\n\n      .progress-wrapper {\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        gap: 8px;\n        width: 80%;\n      }\n\n      .progress {\n        height: 6px;\n        flex-grow: 1;\n        background-color: #444;\n        margin: 0;\n        cursor: pointer;\n        position: relative;\n      }\n\n      .progress-bar {\n        background-color: #1DB954;\n        height: 100%;\n      }\n\n      .time-label {\n        font-size: 0.75rem;\n        color: #888;\n        width: 40px;\n        text-align: center;\n      }\n    <\/style>\n  <\/head>\n  <body>\n    <div id=\"spotifyInfo\">Load Spotify-Data…<\/div>\n\n    <div class=\"controls\" id=\"spotifyControls\" style=\"display:none;\">\n      <div class=\"btn-group-fixed\">\n        <button id=\"shuffleBtn\" class=\"btn\" onclick=\"toggle('shuffle')\">\n          <i class=\"bi bi-shuffle\"><\/i>\n        <\/button>\n        <button class=\"btn\" onclick=\"spotifyControl('previous')\">\n          <i class=\"bi bi-skip-start\"><\/i>\n        <\/button>\n        <button id=\"playPauseBtn\" class=\"btn\" onclick=\"spotifyControl('playpause')\">\n          <i id=\"playPauseIcon\" class=\"bi bi-pause-circle\"><\/i>\n        <\/button>\n        <button class=\"btn\" onclick=\"spotifyControl('next')\">\n          <i class=\"bi bi-skip-end\"><\/i>\n        <\/button>\n        <button id=\"repeatBtn\" class=\"btn\" onclick=\"toggle('repeat')\">\n          <i class=\"bi bi-repeat\"><\/i>\n        <\/button>\n      <\/div>\n\n      <div class=\"progress-wrapper\">\n        <div class=\"time-label\" id=\"timeNow\">0:00<\/div>\n        <div class=\"progress\" id=\"progressBarContainer\" onclick=\"seek(event)\">\n          <div id=\"progressBar\" class=\"progress-bar\" style=\"width: 0%\"><\/div>\n        <\/div>\n        <div class=\"time-label\" id=\"timeTotal\">0:00<\/div>\n      <\/div>\n    <\/div>\n\n    <script>\n      let currentDuration = 0;\n\n      function escapeHtml(text) {\n        return text\n          .replace(\/&\/g, \"&amp;\")\n          .replace(\/<\/g, \"&lt;\")\n          .replace(\/>\/g, \"&gt;\")\n          .replace(\/\"\/g, \"&quot;\")\n          .replace(\/'\/g, \"&#039;\");\n      }\n\n      function secondsToTime(secs) {\n        const m = Math.floor(secs \/ 60);\n        const s = Math.floor(secs % 60);\n        return m + \":\" + (s < 10 ? \"0\" + s : s);\n      }\n\n      async function fetchSpotifyInfo() {\n        const script = `\ntell application \"System Events\"\n  set isRunning to (name of processes) contains \"Spotify\"\nend tell\nif isRunning then\n  tell application \"Spotify\"\n    set tState to player state\n    if tState is playing or tState is paused then\n      set tTrack to current track\n      set tTitle to name of tTrack\n      set tArtist to artist of tTrack\n      try\n        set tAlbum to album of tTrack\n      on error\n        set tAlbum to \"\"\n      end try\n      try\n        set tArt to artwork url of tTrack\n      on error\n        set tArt to \"\"\n      end try\n      set tDuration to duration of tTrack\n      set tPosition to player position\n      set isShuffling to shuffling\n      set isRepeating to repeating\n\n      set json to \"{\"\n      set json to json & \"\\\\\"state\\\\\": \\\\\"\" & tState & \"\\\\\"\"\n      set json to json & \", \\\\\"title\\\\\": \\\\\"\" & tTitle & \"\\\\\"\"\n      set json to json & \", \\\\\"artist\\\\\": \\\\\"\" & tArtist & \"\\\\\"\"\n      set json to json & \", \\\\\"album\\\\\": \\\\\"\" & tAlbum & \"\\\\\"\"\n      set json to json & \", \\\\\"artwork\\\\\": \\\\\"\" & tArt & \"\\\\\"\"\n      set json to json & \", \\\\\"duration\\\\\": \\\\\"\" & (tDuration as string) & \"\\\\\"\"\n      set json to json & \", \\\\\"position\\\\\": \\\\\"\" & (tPosition as string) & \"\\\\\"\"\n      set json to json & \", \\\\\"shuffle\\\\\": \\\\\"\" & (isShuffling as string) & \"\\\\\"\"\n      set json to json & \", \\\\\"repeat\\\\\": \\\\\"\" & (isRepeating as string) & \"\\\\\"\"\n      set json to json & \"}\"\n      return json\n    else\n      return \"{\\\\\"state\\\\\": \\\\\"paused\\\\\"}\"\n    end if\n  end tell\nelse\n  return \"{\\\\\"state\\\\\": \\\\\"not_running\\\\\"}\"\nend if\n        `;\n\n        try {\n          const raw = await runAppleScript(script);\n          const data = JSON.parse(raw);\n\n          const infoDiv = document.getElementById(\"spotifyInfo\");\n          const playPauseIcon = document.getElementById(\"playPauseIcon\");\n          const shuffleBtn = document.getElementById(\"shuffleBtn\");\n          const repeatBtn = document.getElementById(\"repeatBtn\");\n          const controls = document.getElementById(\"spotifyControls\");\n\n          if (data.state === \"not_running\") {\n            infoDiv.innerHTML = \"<p class='error'>Spotify not running...<\/p>\";\n            controls.style.display = \"none\";\n            return;\n          }\n\n          const safeTitle = escapeHtml(data.title || \"\");\n          const safeArtist = escapeHtml(data.artist || \"\");\n          const safeAlbum = escapeHtml(data.album || \"\");\n          const safeArt = escapeHtml(data.artwork || \"\");\n          const durationSec = parseFloat(data.duration) \/ 1000;\n          const positionSec = parseFloat(data.position);\n          const progress = (positionSec \/ durationSec) * 100;\n\n          currentDuration = durationSec;\n\n          const timeNow = secondsToTime(positionSec);\n          const timeTotal = secondsToTime(durationSec);\n\n          const imgTag = safeArt ? `<img src=\"${safeArt}\">` : \"\";\n\n          infoDiv.innerHTML = `\n            ${imgTag}\n            <h1><span class=\"scroll-text ${safeTitle.length > 30 ? 'scroll' : ''}\">${safeTitle}<\/span><\/h1>\n            <h2>${safeArtist} – ${safeAlbum}<\/h2>\n          `;\n\n          document.getElementById(\"progressBar\").style.width = progress + \"%\";\n          document.getElementById(\"timeNow\").innerText = timeNow;\n          document.getElementById(\"timeTotal\").innerText = timeTotal;\n\n          controls.style.display = \"flex\";\n          playPauseIcon.className = data.state === \"paused\" ? \"bi bi-play-circle\" : \"bi bi-pause-circle\";\n          shuffleBtn.classList.toggle(\"active\", data.shuffle === \"true\");\n          repeatBtn.classList.toggle(\"active\", data.repeat === \"true\");\n        } catch (e) {\n          document.getElementById(\"spotifyInfo\").innerHTML = `<p class='error'>Error: ${e}<\/p>`;\n        }\n      }\n\n      function seek(event) {\n        const bar = document.getElementById(\"progressBarContainer\");\n        const rect = bar.getBoundingClientRect();\n        const clickX = event.clientX - rect.left;\n        const percent = clickX \/ rect.width;\n        const newTime = Math.floor(currentDuration * percent);\n\n        const script = `tell application \"Spotify\" to set player position to ${newTime}`;\n        runAppleScript(script).then(() => setTimeout(fetchSpotifyInfo, 400));\n      }\n\n      async function spotifyControl(command) {\n        const cmds = {\n          previous: 'tell application \"Spotify\" to previous track',\n          playpause: 'tell application \"Spotify\" to playpause',\n          next: 'tell application \"Spotify\" to next track',\n        };\n        try {\n          await runAppleScript(cmds[command]);\n          setTimeout(fetchSpotifyInfo, 300);\n        } catch (e) {\n          alert(\"Command error: \" + e);\n        }\n      }\n\n      async function toggle(type) {\n        let script = \"\";\n        if (type === \"shuffle\") {\n          script = 'tell application \"Spotify\" to set shuffling to not shuffling';\n        } else if (type === \"repeat\") {\n          script = `\ntell application \"Spotify\"\n\tif repeating then\n\t\tset repeating to false\n\telse\n\t\tset repeating to true\n\tend if\nend tell\n          `;\n        }\n        try {\n          await runAppleScript(script);\n          setTimeout(fetchSpotifyInfo, 300);\n        } catch (e) {\n          alert(\"Error at toggle: \" + e);\n        }\n      }\n\n      setTimeout(() => {\n        fetchSpotifyInfo();\n        setInterval(fetchSpotifyInfo, 8000);\n      }, 600);\n    <\/script>\n  <\/body>\n<\/html>",
          "BTTMenuItemBorderColorHoverDark" : "255.000, 255.000, 255.000, 255.000",
          "BTTMenuItemWebViewFocusTextField" : 0,
          "BTTMenuCategorySpacing" : 0,
          "BTTMenuAppearanceStyle" : 0,
          "BTTMenuItemBackgroundColorHover" : "0.000, 0.000, 0.000, 0.000",
          "BTTMenuAlwaysUseLightMode" : 1,
          "BTTMenuCategoryBackground" : 0,
          "BTTMenuCategoryItemSizing" : 1,
          "BTTMenuItemSelectedTab" : 778,
          "BTTMenuCategoryResizeOnHover" : 0,
          "BTTMenuCategoryBorder" : 0,
          "BTTMenuHoverStartAnimationDuration" : 0.14999999999999999,
          "BTTMenuCategoryPosition" : 0,
          "BTTMenuUseStyleForSubmenu" : 1,
          "BTTMenuCategoryZIndex" : 0
        },
        "BTTMenuAvailability" : 0,
        "BTTMenuName" : "WebView-Spotify-item",
        "BTTGestureNotes" : "Standard Item"
      }
    ],
    "BTTFloatingMenuRenderedPreview" : "iVBORw0KGgoAAAANSUhEUgAAAMAAAADICAYAAAC+j+5qAAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAABIxlAAAQPgAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAMCgAwAEAAAAAQAAAMgAAAAAtawfqAAAAAlwSFlzAAALBgAACxMBU4EPMAAAC6lJREFUeAHtmttvXFcVxveZM56xHceO4yR2cxFUaSnh0oZWiIsoiigXqapEXypVCP4EJCrxgnhHQkLiD+CJi1AFQpQiHlKJCkRASJFAgkKhauKkJSRt0sZx6ut45vAtd5xatjdeccdTZe_fVr_MeNaaGa_f2t_e+xy3CN1x9OePn2ovtb5XTu55KHSqtZd5hMAdS6Aoi6p9beH83DPT377x9Av_UCH1bjEzerwqzZX2wpFfPP6dYl_jB+Vo83BoM_mNCSMBAlUoamON8YHjYw+2Xrrx3MqVtxZVVSENSfuswtrUjx87VYw2vhWUXLU69hqjFwRKcS6M9TZjLa+sbZNIeCcENKeLYqi8q_nAgUm9v939DFvlDfhkreh0vq+tInDs6aLpxUO7E1rnZ0Ln5nIImthFXaxrZgj9d+u5maMKK_+ZC523lsLKq7PKtYSuevF78BldAoWWd2nzqNXLwyMnWfk3k9npK4Um8OxvzoViXovNUD0MPXw0tK_Nh3JiOJRjjbD04hth4MjeMH_m1VCOD9nGG1ovXw9Fswwjjx1f_dpK12C1kYb8sVXPdvqb8b6tCNRZ+bfC8u5eK8cGQ3tmNgzcOx7mn7sQqmXbeTXVm7oGk0EW__J6CPMrq_O7mlNsYSUUY80wd3o6FMMDYeDusdA8MRGqFQzw7jqx_bs5eG7P6LYyqk4nlPsGQ+PkobDwu1dCZ3YxND58YPUItPLfudA8eTCEVjvU9g9qR9C12Eon1A6PBJ1RQ7X09tGpcXyfJj_XY7cFfofJa7eFdvh23raRQFHUQqVlpfXCtdD8pG6qXbwZls5eDo0HDoWhz46ExTOXQvOhydUjTuvcTGh8aCKEZi2UewdDsace6qOjodDRqVqyXYOx2wTqdlHGatM7zJWOOkMfmwxDD9pNhyIsv_RmKKf2aLVvhkoXx417xldvOFQ63zd0RFL66qgWWqE8OBwG7z_YPTL17nfik6oi1KQtRr39+tylcmrkSKVtmdEbAjbR14ZNcruoXeNbdd7hbK_fGo0yDOuCeXUxsovfLdt1K5snXgJ29225Cp3ry0t6yyaq9dlfn39q9MkPfld3IY5x18FL1Z+3fsJv965qaWW7FOK3QUCzvdBNnvnW5flnb54+f1FvXf3D7_qPMEfcX04N3dc4ceDY+gDPIXDHEyjLqnNjcXHp7BX73yBuSJt2AHvhUWlUemdv1g8MCCRCwOa4nUmnpU1z3O4CjUl2GN20Peg1BgRSIWDze5MB7O8A667EUqmVOiDgI8AfwnycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SOAAXycyEqUAAZItLGU5SNQ96WR1SMCHX2OyUYh2QJkj4z3iAAG6A_4le7XTOhxv2TcZ6Vr0oI0IGEEQej3wAC7T9wm_wnpUeleyQxgY0m6KP1Jer77c6lHRh8JGPCP9PH7cvuqSgXbxP+yNC3ZDvBPaVGy1d80KX1K+pc0J3FdJgg9HtaHGam98XOBvZFI7362s_4p6avS2uS2yX9auir9SDJD2A5wn_R1aVhau0bQU8ZuE2AH2B3CtuIclr4m_Uw6In1Bakg22d8nHZXsSGTPfyXZ0ch2g79JHIUEoYcjugNggB5SXvdRBvyLkp3zfyK9Jn1AMjPYrjsm2aS3+GXpp5JdFNtx6axkr3NRLAg9GlEDcATqEeENH9PUz8elP0t2EWxHHTuD_lGyFd7O_me6zw_o0fpwTjIT3C1tOqvqNcYuEOAuUO+h2mozII1LX5I+IR3q6ik9HpTukr4p7ZfsKPQNyVZ8y7P3cR0gCP0YGGB3KJsJbBW3480VyVb4vdIFyWJ2BLLntjuYCey5GeCYZJOf448g9GNggN5TtslrZ_g3pX9Lv5VsFxiVfil9XDIz2PWAXRgPS89I9prF7A4RR1NB6McA9O5QtpXdbnl+RhqU7GxvZ_0npEckW+m_In1aui7ZrvBRyRakCxJ3gQShH4O7QLtH2S50Py_ZZH+4+7hHjwuSnfPnJdsZ7Dhkt0nNDH+QXpTYmQWhh8MWGP4Q1kOg232UHYNsZbdjjpngkvRD6Q3p99K0ZLc7bbLb65+T7Fbp85JdQDP6RMAa9WSfvivHr2mr6JNdxrYjvF+6KdmxyHZfu0C2XcGuFZ6WWhLHUkHo8bAbCxek5Y2fy1a7kUhvf7ZJ_lfpFekRyS6EpyRbeMwIti0_K_1dsonP5BeEfg52gP7QthXIVvemZCu+GWNRmpNscOx5m8Nu_csOsFtknZ9rK7tNfhu28tuwxYeJv4rivfuHI1D_2XPM6T_z6DfSjCgaAjkQwAA5dJkaowQwQBQNgRwIYIAcukyNUQIYIIqGQA4EMEAOXabGKAEMEEVDIAcCGCCHLlNjlAAGiKIhkAMBDJBDl6kxSgADRNEQyIEABsihy9QYJYABomgI5EAAA+TQZWqMEsAAUTQEciCAAXLoMjVGCWCAKBoCORDAADl0mRqjBDBAFA2BHAhggBy6TI1RAhggioZADgQwQA5dpsYoAQwQRUMgBwIYIIcuU2OUAAaIoiGQAwEMkEOXqTFKAANE0RDIgQAGyKHL1BglgAGiaAjkQAAD5NBlaowSwABRNARyIIABcugyNUYJYIAoGgI5EMAAOXSZGqMEMEAUDYEcCGCAHLpMjVECGCCKhkAOBDBADl2mxigBDBBFQyAHAhgghy5TY5QABoiiIZADAQyQQ5epMUoAA0TREMiBAAbIocvUGCWAAaJoCORAAAPk0GVqjBLAAFE0BHIggAFy6DI1RglggCgaAjkQwAA5dJkaowQwQBQNgRwIYIAcukyNUQIYIIqGQA4EMEAOXabGKAEMEEVDIAcCGCCHLlNjlAAGiKIhkAMBDJBDl6kxSgADRNEQyIEABsihy9QYJYABomgI5EAAA+TQZWqMEsAAUTQEciCAAXLoMjVGCWCAKBoCORDAADl0mRqjBDBAFA2BHAhggBy6TI1RAhggioZADgQwQA5dpsYoAQwQRUMgBwIYIIcuU2OUAAaIoiGQAwEMkEOXqTFKAANE0RDIgQAGyKHL1BglgAGiaAjkQAAD5NBlaowSwABRNARyIIABcugyNUYJYIAoGgI5EKiryOvShFTlUDA1ZkegUMUtqb1V5WaAl6WONLhVAq9B4A4nYBN_Rooa4IqCI3d4kfz6EPh_BGwX2Gp01gJTiprsZ45CW6HitZQI2Dy3HeG1NQNYcXukSWlMwgSCwEiWgB2Jrkpz_wPjqaqF1qorJgAAAABJRU5ErkJggg==",
    "BTTMenuConfig" : {
      "BTTMenuBringToFrontOnHover" : 0,
      "BTTMenuOnlyUpdatePositionOnExplicitRequest" : 1,
      "BTTMenuVerticalSpacing" : 0,
      "BTTMenuAnchorRelation" : 0,
      "BTTMenuItemBackgroundColor" : "33.000000, 33.000000, 33.000000, 255.000000",
      "BTTMenuOffsetXUnit" : 2,
      "BTTMenuCategoryItemVisibility" : 0,
      "BTTMenuSelectedTab" : 0,
      "BTTMenuPositioningType" : 1,
      "BTTMenuItemBorderWidth" : 0,
      "BTTMenuCategoryResizeOnHover" : 0,
      "BTTMenuPositionRelativeTo" : 8,
      "BTTMenuCategoryOnlyShowIf" : 0,
      "BTTMenuCategoryModifiers" : 0,
      "BTTMenuOffsetX" : 30,
      "BTTMenuOffsetY" : -15,
      "BTTMenuItemShadowEnabled" : 1,
      "BTTMenuItemCornerRadius" : 10,
      "BTTMenuFrameWidth" : 530,
      "BTTMenuFrameHeight" : 530,
      "BTTMenuCategoryShadow" : 0,
      "BTTMenuItemBorderColor" : "33.110, 33.111, 33.110, 255.000",
      "BTTMenuCategoryBackground" : 0,
      "BTTMenuScreenUUID" : "37D8832A-2D66-02CA-B9F7-8F30A301B230",
      "BTTMenuItemPaddingTop" : 0,
      "BTTMenuCategoryItemBehavior" : 0,
      "BTTMenuItemSelectedTab" : 0,
      "BTTMenuCategoryZIndex" : 1,
      "BTTMenuUseStyleForSubmenu" : 1,
      "BTTMenuCategoryItemSpacing" : 0,
      "BTTMenuItemScriptActive" : 0,
      "BTTMenuVisibility" : 1,
      "BTTMenuItemsUseModifierModes" : false,
      "BTTMenuCategoryMenuOpacity" : 0,
      "BTTMenuItemBlurredBackground" : 0,
      "BTTMenuCloseOnOutsideClick" : 0,
      "BTTMenuLayoutDirection" : 0,
      "BTTMenuScriptSettings" : {
        "BTTScriptType" : 3,
        "BTTAppleScriptString" : "\/\/\n\/\/returnToBTT('please return a string like this somewhere in your Java Script or use an async function instead');",
        "BTTScriptLocation" : 0,
        "BTTAppleScriptUsePath" : false,
        "BTTJavaScriptUseIsolatedContext" : false
      },
      "BTTMenuItemBackgroundType" : 0,
      "BTTMenuItemPaddingLeft" : 0,
      "BTTMenuTitleBarStyle" : 2,
      "BTTMenuItemBackgroundColorHover" : "33.000000, 33.000000, 33.000000, 255.000000",
      "BTTMenuHorizontalSpacing" : 0,
      "BTTMenuCategoryMenuVisibility" : 0,
      "BTTMenuWindowLevel" : 3,
      "BTTMenuCategoryBorder" : 0,
      "BTTMenuItemPaddingRight" : 0,
      "BTTMenuModifierMode" : 3,
      "BTTMenuSizingBehavior" : 0,
      "BTTMenuCloseAfterAction" : 0,
      "BTTMenuWindowResizable" : 0,
      "BTTMenuAnchorMenu" : 0,
      "BTTMenuShowIfWindowLevelEqualsEnabled" : 0,
      "BTTMenuCategoryItemSizing" : 0,
      "BTTMenuAppearanceStyle" : 0,
      "BTTMenuItemBorderColorHover" : "66.432, 66.434, 66.433, 255.000",
      "BTTMenuAvailability" : 1,
      "BTTMenuStealKeyboardFocusOnShow" : 1,
      "BTTLastChangeUUID" : "83580B18-7F25-4060-9C11-75D15C062A11",
      "BTTMenuCategorySpacing" : 0,
      "BTTMenuElementIdentifier" : "WebView-Spotify",
      "BTTMenuCategoryPosition" : 0,
      "BTTMenuItemPaddingBottom" : 0,
      "BTTMenuAlwaysUseLightMode" : 1,
      "BTTMenuCategoryItemIcon" : 0,
      "BTTMenuOffsetYUnit" : 2,
      "BTTMenuCategorySize" : 0
    },
    "BTTMenuAvailability" : 1,
    "BTTMenuName" : "WebView-Spotify"
  }
]

ah, on macOS I allow a (optional) simplified syntax that doesn't require parameters - this is not yet implemented on iOS.

If you change this line:

          const raw = await runAppleScript(script);

To this:

          const raw = await runAppleScript({script: script});

it should work.

It's possible there are still other things missing, the webview is not yet fully implemented.

Great Andreas !
that works...

you are right, when all those other "runAppleScript" items
like: await runAppleScript({script: cmds[command]});
etc. are changed as well it runs fine from BTT Mobile !

1 Like