Google 脚本:当特定单元格更改值时播放声音

问题描述 投票:0回答:3

情况:

电子表格示例

表:支持
列:H 具有以下函数 "=IF(D:D>0;IF($B$1>=$G:G;"Call";"In Time");" ")",根据情况更改值关于结果。

问题:

我需要:

  1. 当“支持”工作表上 H 列中的单元格更改为“呼叫”时播放声音。
  2. 此功能需要每 5 分钟运行一次。
  3. 声音是否需要上传到云端硬盘,或者我可以使用 URL 中的声音吗?

我将感谢任何人可以提供帮助...我看到很多代码,但我不太理解。

javascript audio google-apps-script google-sheets
3个回答
7
投票

这是一个非常棘手的问题,但可以通过侧边栏定期轮询 H 列以了解更改来完成。

代码.gs

// creates a custom menu when the spreadsheet is opened
function onOpen() {
  var ui = SpreadsheetApp.getUi()
    .createMenu('Call App')
    .addItem('Open Call Notifier', 'openCallNotifier')
    .addToUi();

  // you could also open the call notifier sidebar when the spreadsheet opens
  // if you find that more convenient
  // openCallNotifier();
}

// opens the sidebar app
function openCallNotifier() {
  // get the html from the file called "Page.html"
  var html = HtmlService.createHtmlOutputFromFile('Page') 
    .setTitle("Call Notifier");

  // open the sidebar
  SpreadsheetApp.getUi()
    .showSidebar(html);
}

// returns a list of values in column H
function getColumnH() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Support");

  // get the values in column H and turn the rows into a single values
  return sheet.getRange(1, 8, sheet.getLastRow(), 1).getValues().map(function (row) { return row[0]; });
}

Page.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <p id="message">Checking for calls...</p>

    <audio id="call">
      <source src="||a URL is best here||" type="audio/mp3">
      Your browser does not support the audio element.
    </audio>

    <script>
    var lastTime = []; // store the last result to track changes

    function checkCalls() {

      // This calls the "getColumnH" function on the server
      // Then it waits for the results
      // When it gets the results back from the server,
      // it calls the callback function passed into withSuccessHandler
      google.script.run.withSuccessHandler(function (columnH) {
        for (var i = 0; i < columnH.length; i++) {

          // if there's a difference and it's a call, notify the user
          if (lastTime[i] !== columnH[i] && columnH[i] === "Call") {
            notify();
          }
        }

        // store results for next time
        lastTime = columnH;

        console.log(lastTime);

        // poll again in x miliseconds
        var x = 1000; // 1 second
        window.setTimeout(checkCalls, x);
      }).getColumnH();
    }

    function notify() {
      document.getElementById("call").play();
    }

    window.onload = function () {
      checkCalls();
    }

    </script>
  </body>
</html>

一些有帮助的来源:


2
投票

当我实现给出的主要答案时,递归调用 checkCalls() 最终导致错误(这基本上是正确的并且非常有用,所以谢谢!)。

// 注意:但是最初的实现可以正常工作一段时间 - 比如说 90 分钟 - 然后崩溃。通常需要 1 秒的调用将花费 300 秒,并且执行将停止。看起来它通过不断递归调用自身而导致堆栈崩溃。当转移到一次 check() 调用并正确退出该函数时,它就可以工作了。

运行 JavaScript 时登录 Chrome 的控制台是这样的: ERR_QUIC_PROTOCOL_ERROR.QUIC_TOO_MANY_RTOS 200

经过大量调查,我找到了一种更好的方法......它不需要递归(因此不会破坏堆栈)。

删除这一行: // window.setTimeout(checkCalls, 500);

并在脚本末尾使用类似的内容:

  // This function returns a Promise that resolves after "ms" Milliseconds

        // The current best practice is to create a Promise...
  function timer(ms) {
   return new Promise(res => setTimeout(res, ms));
  }

  
  async function loopthis () { // We need to wrap the loop into an async function for the await call (to the Promise) to work.  [From web: "An async function is a function declared with the async keyword. Async functions are instances of the AsyncFunction constructor, and the await keyword is permitted within them. The async and await keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains."]
    for (var i = 0; i >= 0; i++) {
      console.log('Number of times function has been run: ' + i);
      checkCalls();
      await timer(3000);
    }
  }


  window.onload = function () {
    loopthis();
  }

</script>

0
投票

我也想在我的项目中实现这个未来。我采用了 Joshua Dawson 的想法,即使用侧边栏来播放音频。然而,我并不相信 Rob Blakemore 的无限循环想法,即每次迭代都会调用等待函数。相反,已经实现了一个函数:setInterval 请参阅在线文档了解更多详细信息。下面是我的代码示例,需要添加到 HTML 文件部分的末尾。

  function runEverySecond() {
  //This function checkCalls() is triggered every second
    setInterval(function() {
      checkCalls();
    }, 1000); // 1000 milliseconds = 1 seconds
  }

  window.onload = function () {
    runEverySecond()
  }

© www.soinside.com 2019 - 2024. All rights reserved.