5

On my WordPress site I have a form that converts text to audio using AJAX and PHP. The file name remains the same when the converted text is updated, it just recreates the file.

Everything seems to work fine except that the audio source to be played is not being reloaded/refresh when I update the text.

The default download button gives me the updated file and if I refresh the whole page, I can only then hear the updated file playing.

My code (simplified for relevance) --

jQuery(document).on('click', '#savetext', function(e) {
  e.preventDefault();
  var myVideo = $('#player');
  var path = $("#path").val();
  myVideo.src = path;

  $.ajax({
    data: {
      action: 'polly_pros',
      pollytext: txt,
      rate: rate,
      voice: voice
    },
    type: 'post',
    url: polpro.ajax_url,
    cache: false,
    success: function(data) {
      console.log(data);
      myVideo.load();
      myVideo.get(0).play();
    },
    error: function() {
      console.log("Error");
    }
  });
});
<audio id="player" controls>
  <source id="audiosource" src="<?php echo $thepath; ?>" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>

<textarea name="pollytext" id="pollytext"></textarea>
<button type="submit" id="savetext" name="savetext">save text</button>

How can I make it so that when the file is updated, so is the audio that plays?

UPDATE

I tried the following suggestion but it didnt fix the issue -

 $.ajax ({        
         data: {
          action: 'polly_pros', 
          pollytext: txt,
          rate: rate,
          voice: voice
        },
         type: 'post',
         url: polpro.ajax_url,
         cache: false,
       success: function(data) {
           console.log(data);
 myVideo.src = path+"&rnd="+new Date().getTime();
myVideo.load();
myVideo.get(0).play();
        },
          error: function() {
            console.log("Error");            
        }
            });
730wavy
  • 944
  • 1
  • 19
  • 57
  • Try appending a timestamp to the `src`, or dynamically deleting/recreating the `audio` element. Also, setting expiration headers of the file on the server would help too. – Rory McCrossan May 11 '18 at 16:31
  • Im still quite new to ajax, can you please provide some kind of example with your suggestions? @RoryMcCrossan – 730wavy May 11 '18 at 16:32
  • `success: function(data) { console.log(data); myVideo.src = path+"&rnd="+new Date().getTime(); myVideo.load(); myVideo.get(0).play(); }` – mplungjan May 11 '18 at 16:41
  • I updated my question with your tried suggestion. It didnt work though. @mplungjan – 730wavy May 11 '18 at 16:57
  • "it didn't work" The most useless statement at SO. What happened? Errors in console? Server errors? What does myVideo.load() do - why is it not enough to just change source and use play? – mplungjan May 11 '18 at 17:08
  • So is your attitude and trying to comment an answer and have a discussion about it in the comments. Maybe you should put your comment as an answer and explain your code so I can understand. As far as your comment though, it didnt work or show errors. After messing with it for a while I see that it seems to work but with a long delay and several button clicks. There's no indication of anything going right or wrong.@mplungjan – 730wavy May 11 '18 at 17:24
  • @mplungjan and what do you mean just change source and play? The source file remains the same, it just gets updated and recreated. – 730wavy May 11 '18 at 17:33
  • My addition keeps it from being cached – mplungjan May 11 '18 at 17:34
  • Try this instead: `var path = $("#path").val(); myVideo.src = path+"&rnd="+new Date().getTime();` - it sounds to me as if you just need to not cache the file – mplungjan May 11 '18 at 20:29
  • And my comment was really because I try to help but then have to add another question to hear if there are errors or whatever. Please never comment on a suggestion with just "It doesn't work" Ok? :) – mplungjan May 11 '18 at 20:31
  • @mplungjan if it gives no error or any indication what else can I really say? lol. – 730wavy May 12 '18 at 02:58
  • how is that different from the other code? @mplungjan – 730wavy May 12 '18 at 03:10
  • I moved the statement – mplungjan May 12 '18 at 04:05
  • So last suggestion- return the name of a new file and load that instead. Have the server generate a new file name each time or send caching directives – mplungjan May 12 '18 at 04:06
  • it didnt work and it gave no errors in the console. @mplungjan – 730wavy May 12 '18 at 07:18
  • So whatever you do it plays the old file itself? – Tarun Lalwani May 18 '18 at 13:26
  • @TarunLalwani on initial page load it works the first time, then if i try it again it doesnt play the recreated new file as it should. There's a very long delay. So the suggestion is on the right track but it takes way too long and too many tries and button presses. – 730wavy May 18 '18 at 15:34
  • What happens if you remove `myVideo.load();`? Also I would try creating a new element removing the old and adding the new element and see if that helps – Tarun Lalwani May 18 '18 at 15:43
  • 1
    can you elaborate on your second suggestion? – 730wavy May 18 '18 at 16:09
  • @TarunLalwani it stops working at all – 730wavy May 18 '18 at 20:55
  • Not sure if `myVideo.load();` was a typo in your question, but try changing it to `myVideo.get(0).load();` which would properly call the `load()` method of the `audio` element, and not [`jQuery.load()`](http://api.jquery.com/load/). – Sally CJ May 25 '18 at 14:19
  • I already have it as -- `$("#player")[0].load();` @SallyCJ – 730wavy May 25 '18 at 16:19
  • In that case, please check this [Pen](https://codepen.io/anon/pen/ZodaQe/left?editors=1011#0) and see if the code in between `// -- start --` and `// -- end --` helps. – Sally CJ May 25 '18 at 16:54
  • the issue is because the audio source is a file that can be updated using a form. So your solution will work if I was actually changing it to a different file. @SallyCJ – 730wavy May 26 '18 at 06:23
  • I hope I can see a sample of a real page on your site, but I'm guessing that the problem might be in the back-end. A caching issue, maybe. – Sally CJ May 27 '18 at 01:35

4 Answers4

1

I would try a different approach to try to solve this, first, instead of reloading the src of the audio, you can try re-creating the whole element and then load() and play() the new element (extracted from here: jQuery/JavaScript Change Audio Source dynamically ), like this:

$.ajax ({        
        data: {
          action: 'polly_pros', 
          pollytext: txt,
          rate: rate,
          voice: voice
        },
        type: 'post',
        url: polpro.ajax_url,
        cache: false,
        success: function(data) {
           console.log(data);

           var newAudio = $(createAudio(path));
           $("#player").replaceWith(newAudio);
           $("#player").load();
           newAudio.play();
        },
        error: function() {
           console.log("Error");            
        }
});

function createAudio(src) {
  output =  '<audio id="player">';
  // you can add more source tag
  output +=  '<source src='+src+'" type="audio/mp3" />';
  output +=  '</audio>';
}

If this doesn't work, I would try doing this to play the audio when the mouse enter the element (extracted from here: Loading Audio Element After Dynamically Changing the Source):

var audio = $("#audio")[0];
$("#audio").mouseenter(function () {
   audio.load();
   audio.play();
});

If nothing of above works you can try like this guy (jQuery/JavaScript Change Audio Source dynamically) did a similar aproach and finally make it work doing it with pure javascript (last answer) like:

var audioElement = document.getElementById('audio');
audioElement.setAttribute('src', src);
// Load src of the audio file
audioElement.load();
audioElement.play();

Hope it helps!

JP. Aulet
  • 4,375
  • 4
  • 26
  • 39
1

Most probably it is because the function called by Ajax only reloads the file but does not save a new one. So browser does not reload this file.

Here is a solution

You have to add random string by the end of the file name so that browser would think that this is a different file and reload it

jQuery(document).on('click', '#savetext', function(e) {
  e.preventDefault();
  var myVideo = $('#player');
  var path = $("#path").val();
  myVideo.src = path + "?" + new Date().getTime();

  $.ajax({
    data: {
      action: 'polly_pros',
      pollytext: txt,
      rate: rate,
      voice: voice
    },
    type: 'post',
    url: polpro.ajax_url,
    cache: false,
    success: function(data) {
      console.log(data);
      myVideo.load();
      myVideo.get(0).play();
    },
    error: function() {
      console.log("Error");
    }
  });
});

Timestamp is the number you know for sure that will be different every time.

EDIT

If it works sometimes and sometimes not, it probably means that sometimes Ajax is faster and sometimes slower. This should help

jQuery(document).on('click', '#savetext', function(e) {
  e.preventDefault();
  var myVideo = $('#player');

  $.ajax({
    data: {
      action: 'polly_pros',
      pollytext: txt,
      rate: rate,
      voice: voice
    },
    type: 'post',
    url: polpro.ajax_url,
    cache: false,
    success: function(data) {
      console.log(data);
      var path = $("#path").val();
      myVideo.src = path + "?" + new Date().getTime();
      myVideo.load();
      myVideo.get(0).play();
    },
    error: function() {
      console.log("Error");
    }
  });
});
Krzysztof Janiszewski
  • 3,763
  • 3
  • 18
  • 38
  • Im testing now. It seems to work but with delays so its inconsistent. Can you please explain what is new date and get time actually doing to make the browser reload the file? – 730wavy May 24 '18 at 13:12
  • 2
    I did. This is just a random string at the end of the file name. Browser gets different file name and reloads it. If it gets the same name there is no need for reloading the file. I don't know why are the delays maybe because of Ajax? The question mark is the same as is used in browser url, so this is just a variable. That's why it does not really change anything. Just the fact that browser thinks it's a different file. – Krzysztof Janiszewski May 24 '18 at 13:16
  • 2
    `new Date()` creates new date object with current datetime. `getTime()` gets timestamp from date object. So it probably looks smoething like this `1527167853296`. It does not have to be a date, but this way you are sure that it is different every time. – Krzysztof Janiszewski May 24 '18 at 13:18
  • is there anyway to use something that changes more frequently than the date? – 730wavy May 24 '18 at 13:25
  • 1
    I don't know anything faster than miliseconds in JavaScript or jQuery. And timestamp is a full datetime, so it has also miliseconds. Try my edited answer, it should work now every time. – Krzysztof Janiszewski May 24 '18 at 13:27
  • @Rich if it helped you then please upvote, because if you won't the reputation won't be assigned to anyone, – Krzysztof Janiszewski May 25 '18 at 09:58
  • I accepted the answer but it still gives me the same issue with the delay. – 730wavy May 25 '18 at 13:19
  • Hmm, even after the edit? What exactly is the problem? What delay do you reffer to? Did you check dev tools `network` tab? Perhaps it's just the time for Ajax to process? – Krzysztof Janiszewski May 25 '18 at 13:26
0

Add a timestamp in url path, while having the XHR call. If it does not work, then add prevent cache header in server side. Hope it will work.

$.ajax({
  data: {
    action: 'polly_pros',
    pollytext: txt,
    rate: rate,
    voice: voice
  },
  type: 'post',
  url: polpro.ajax_url + "&rnd=" + new Date().getTime(), //timestamp
  cache: false,
  success: function(data) {
    console.log(data);
    myVideo.src = path + "&rnd=" + new Date().getTime(); //timestamp
    myVideo.load();
    myVideo.get(0).play();
  },
  error: function() {
    console.log("Error");
  }
});
Jay
  • 338
  • 1
  • 5
0

Depending on your approach and wishes for how everything is set up on your page, you could have a "div" area on your page that you refresh with an AJAX type GET on your page. That way you will have reloaded the video into your page, and then proceed with your "play" function as you normally would.

What it would take to achieve this is to have seperate file for the general page where everything takes place, and the have the video itself in another file that is loaded on success with AJAX type GET.

I am suggesting this because my suspicion is that you are trying to play an element (video) that is not properly loaded. I'm sorry if I misunderstood anything.

Martin
  • 2,326
  • 1
  • 12
  • 22