Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Is it possible to play a mp3 file?
-
I am trying the very same, but for some reason my code does not work. I tried with .m4a and .mp3 files. Any ideas why?
import os import sound path = os.listdir()[0] mp3 = sound.Player(path) mp3.play()
os.listdir() returns [‘testmpthree.mp3’, ‘Play.py’]
The error lies in line 4, the error is string object not callable -
@Drizzel I have the same IF I do that:
mp3 = sound.Player(path())
Traceback (most recent call last):
File "/private/var/mobile/Containers/Shared/AppGroup/668A7D98-7216-47ED-917D-AA0B6173167E/Pythonista3/Documents/test5.py", line 4, in <module>
mp3 = sound.Player(path())
TypeError: 'str' object is not callable -
@cvp No idea why, but I put the brackets, ran it once, got the error, removed the brackets, restarted pythonista, ran it, and it worked. Honestly, I can’t explain it. Nevertheless, thanks a lot.
However, it won’t run m4a files (it doesn’t give me an error, but I just don’t hear anything). Do you know how to fix that? Or do I have to convert it to mp3 first? -
-
@Drizzel have you tried looking at it in the file browser? Does the quicklook play it?
Also, does youtubedl write the file, or just give you bytes? If you write the file yourself be sure to open it in binary write mode.
I read somewhere that youtubedl might sometimes have nonstandard headers in m4a files that need to get fixed. iOS does support m4a.
-
I can play the audio if I manually quickplay it in the file browser.
This here is the code to download and play a song from YouTube:
from __future__ import unicode_literals import youtube_dl import os from sys import argv # Download data and config download_options = { 'format': 'm4a', 'outtmpl': '%(title)s.%(ext)s', 'nocheckcertificate': True, 'preferredcodec': 'best', } # Download Songs with youtube_dl.YoutubeDL(download_options) as dl: with open('songs.txt', 'r') as f: for song_url in f: dl.download([song_url]) import sound path = os.listdir()[0] audio = sound.Player(path) audio.play() print(audio.playing)
songs.txt just contains some links to music on YouTube.
Every time I run this, I get this message:
WARNING: aAiVsqfbn5g: writing DASH m4a. Only some players support this container. Install ffmpeg or avconv to fix this automatically.
The last line of code always prints that the Audio is not playing when trying it with m4a fields downloaded from YouTube. The file @cvp used works flawlessly, just as some mp3 file I used for testing.
Thanks a lot for trying to solve this, really -
is your goal just to play it? or play it in a scene or something?
You could try opening it in a webview, (pass the os.path.abspath(path) to webview.load_url)
-
My goal is just play it offline, I’m trying to code something of a Spotify alternative for myself. Although I will at some point implement it in a ui
-
@Drizzel you can use Webview with a file
import ui import os v = ui.WebView() v.present('sheet') v.load_url(os.path.abspath('sample.m4a'))
-
@cvp great, that actually works :)
Is there any way to stop, skip, and see information like how long the audio is and for how long it has been playing for? I have been searching for these things, but I can’t really find them. There is a stop() function, but for some reason it doesn’t change anything -
-
I suppose you have set the frame bigger, so you see all buttons of a player
-
You ought to be able to write a JavaScript or HTML 5 player, which you could then control via python using be eval_js. I suspect you can find someone's jukebox JavaScript code that you could just use.
-
A good begin to find here
-
Thanks a lot to both of you, that helped me loads! My html skills are rather limited and JavaScript is absolutely unfamiliar to me, but I will manage somehow, now that I have a good base I can start from :)
-
@Drizzel very quick and dirty sample, that's the first time I use js 😢
import ui import os import time import threading class my_thread(threading.Thread): def __init__(self,my_view): threading.Thread.__init__(self) self.my_view = my_view def run(self): while not self.stop: time.sleep(1) try: d = webview.eval_js('document.getElementById("myaudio").duration;') if d == 'NaN': continue c = webview.eval_js('document.getElementById("myaudio").currentTime;') c = float(c) d = float(d) self.my_view['currentTime'].value = c/d self.my_view['timers'].text = str(int(c)) + '/' + str(int(d)) + ' sec.' except Exception as e: pass path = 'Johnny Rivers - John Lee Hooker - Live At The Whiskey A Go Go.mp3' absfilepath=os.path.abspath(path) TEMPLATE=''' <audio id="myaudio" autoplay preload="auto"> <source src="file://{{FPATH}}" type="audio/mp3"> </audio> ''' webview = ui.WebView(name='webview') bplay = ui.ButtonItem() bplay.image = ui.Image.named('iob:play_32') def bplay_action(sender): webview.eval_js('document.getElementById("myaudio").play();') bplay.action = bplay_action bpause = ui.ButtonItem() bpause.image = ui.Image.named('iob:ios7_pause_32') def bpause_action(sender): webview.eval_js('document.getElementById("myaudio").pause();') bpause.action = bpause_action bstop = ui.ButtonItem() bstop.image = ui.Image.named('iob:stop_32') def bstop_action(sender): # audio player of html5 does not have a stop function webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') bstop.action = bstop_action webview.right_button_items = [bplay,bpause,bstop] currentTime = ui.Slider(name='currentTime') currentTime.frame = (10,10,200,32) def currentTime_action(sender): d = webview.eval_js('document.getElementById("myaudio").duration;') c = currentTime.value * float(d) webview.eval_js('document.getElementById("myaudio").currentTime = ' + str(c) + ';') currentTime.action = currentTime_action webview.add_subview(currentTime) timers = ui.Label(name='timers') timers.frame = (220,10,370,32) webview.add_subview(timers) html = TEMPLATE.replace('{{FPATH}}', absfilepath) webview.load_html(html) webview.name = path webview.frame = (0,0,600,100) webview.present('sheet') t = my_thread(webview) t.stop = False t.start() webview.wait_modal() # force stop player if not done webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') t.stop = True # force end of thread```
-
@cvp impressive, I wouldn’t have managed that this quickly :)
This question may be a bit off topic, but do you have any idea why YouTube-dl downloads files with twice the length of the original YouTube video? The first half contains the audio, and the second half simply contains no sound.
from __future__ import unicode_literals import youtube_dl import os from sys import argv # Download data and config download_options = { 'format': 'm4a', 'outtmpl': '%(title)s.%(ext)s', 'nocheckcertificate': True, 'preferredcodec': 'best', } # Download Songs with youtube_dl.YoutubeDL(download_options) as dl: with open('songs.txt', 'r') as f: for song_url in f: dl.download([song_url])
-
@Drizzel No idea but a Google search on "youtube m4a double size" shows you aren't alone with this problem...
-
import ui import os import time import threading class my_thread(threading.Thread): def __init__(self,my_view): threading.Thread.__init__(self) self.my_view = my_view def run(self): while not self.stop: time.sleep(1) try: d = webview.eval_js('document.getElementById("myaudio").duration;') if d == 'NaN': continue c = webview.eval_js('document.getElementById("myaudio").currentTime;') c = float(c) d = float(d) self.my_view['currentTime'].value = c/d self.my_view['timers'].text = str(int(c)) + '/' + str(int(d)) + ' sec.' except Exception as e: pass path = 'Johnny Rivers - John Lee Hooker - Live At The Whiskey A Go Go.mp3' absfilepath=os.path.abspath(path) TEMPLATE=''' <audio id="myaudio" autoplay preload="auto"> <source src="file://{{FPATH}}" type="audio/mp3"> </audio> ''' webview = ui.WebView(name='webview') bplay = ui.ButtonItem() bplay.image = ui.Image.named('iob:play_32') def bplay_action(sender): webview.eval_js('document.getElementById("myaudio").play();') bplay.action = bplay_action bpause = ui.ButtonItem() bpause.image = ui.Image.named('iob:ios7_pause_32') def bpause_action(sender): webview.eval_js('document.getElementById("myaudio").pause();') bpause.action = bpause_action bstop = ui.ButtonItem() bstop.image = ui.Image.named('iob:stop_32') def bstop_action(sender): # audio player of html5 does not have a stop function webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') bstop.action = bstop_action webview.right_button_items = [bplay,bpause,bstop] currentTime = ui.Slider(name='currentTime') currentTime.frame = (10,10,200,32) def currentTime_action(sender): d = webview.eval_js('document.getElementById("myaudio").duration;') c = currentTime.value * float(d) webview.eval_js('document.getElementById("myaudio").currentTime = ' + str(c) + ';') currentTime.action = currentTime_action webview.add_subview(currentTime) timers = ui.Label(name='timers') timers.frame = (220,10,370,32) webview.add_subview(timers) html = TEMPLATE.replace('{{FPATH}}', absfilepath) webview.load_html(html) webview.name = path webview.frame = (0,0,600,100) webview.present('sheet') t = my_thread(webview) t.stop = False t.start() webview.wait_modal() # force stop player if not done webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') t.stop = True # force end of thread```
Apologies if this seems like a stupid question, but how do I another song? Like, if a ui button is pressed, another song starts playing. I’m relatively new to coding in general, as I started learning python 2 years ago
-
@Drizzel try this
import ui import os import time import threading class my_thread(threading.Thread): def __init__(self,my_view): threading.Thread.__init__(self) self.my_view = my_view def run(self): while not self.stop: time.sleep(1) try: d = webview.eval_js('document.getElementById("myaudio").duration;') if d == 'NaN': continue c = webview.eval_js('document.getElementById("myaudio").currentTime;') c = float(c) d = float(d) self.my_view['currentTime'].value = c/d self.my_view['timers'].text = str(int(c)) + '/' + str(int(d)) + ' sec.' except Exception as e: pass paths = os.listdir() musics = [] for path in paths: if path[-4:].lower() in ('.mp3','.m4a'): musics.append(path) #print(musics) i_music = 0 TEMPLATE=''' <audio id="myaudio" autoplay preload="auto"> <source src="file://{{FPATH}}" type="audio/mp3"> </audio> ''' webview = ui.WebView(name='webview') def set_music(): path = musics[i_music] absfilepath=os.path.abspath(path) html = TEMPLATE.replace('{{FPATH}}', absfilepath) webview.load_html(html) webview.name = path bplay = ui.ButtonItem() bplay.image = ui.Image.named('iob:play_32') def bplay_action(sender): webview.eval_js('document.getElementById("myaudio").play();') bplay.action = bplay_action bpause = ui.ButtonItem() bpause.image = ui.Image.named('iob:ios7_pause_32') def bpause_action(sender): webview.eval_js('document.getElementById("myaudio").pause();') bpause.action = bpause_action bstop = ui.ButtonItem() bstop.image = ui.Image.named('iob:stop_32') def bstop_action(sender): # audio player of html5 does not have a stop function webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') bstop.action = bstop_action bnext = ui.ButtonItem() bnext.image = ui.Image.named('iob:ios7_skipforward_32') def bnext_action(sender): global i_music bstop_action('simulate') i_music = i_music + 1 if i_music >= len(musics): i_music = 0 set_music() bnext.action = bnext_action webview.right_button_items = [bplay,bpause,bstop,bnext] currentTime = ui.Slider(name='currentTime') currentTime.frame = (10,10,200,32) def currentTime_action(sender): d = webview.eval_js('document.getElementById("myaudio").duration;') c = currentTime.value * float(d) webview.eval_js('document.getElementById("myaudio").currentTime = ' + str(c) + ';') currentTime.action = currentTime_action webview.add_subview(currentTime) timers = ui.Label(name='timers') timers.frame = (220,10,370,32) webview.add_subview(timers) webview.frame = (0,0,600,100) set_music() webview.present('sheet') #time.sleep(0.5) t = my_thread(webview) t.stop = False t.start() webview.wait_modal() # force stop player if not done webview.eval_js('document.getElementById("myaudio").pause();') webview.eval_js('document.getElementById("myaudio").currentTime = 0;') t.stop = True # force end of thread