Processing audio of url stream in unspecified format - python

I'm trying to process url audio streams from list of urls. Each url can have different format and I'm trying to find a library that can handle all the format kinds and give me the raw stream data that I can then process.
I have a code that can process wav stream. the problem is that some urls are in aac or mp3 formats and I need to handle each one of them correctly.
This is the code to process wav stream:
from urllib2 import urlopen
#to python3.x
#from urllib.request import urlopen
import pyaudio
pyaud = pyaudio.PyAudio()
srate=44100
stream = pyaud.open(format = pyaud.get_format_from_width(1),
channels = 1,
rate = srate,
output = True)
url = "http://myurl/hara.wav"
u = urlopen(url)
data = u.read(8192)
while data:
stream.write(data)
data = u.read(8192)
This code currently fails when the format is not wav. I tried reading about ffmpeg or vlc to format the urls but I haven't found a working way.
Any help would be appreciated. :)

Related

Can't send BytesIO to Telegram bot:

Situation.
I need to create in-memory csv file and send it to bot.
According to this article and bot documentation I assume I can send csv files. Difference: i use another api wrapper: telebot. According to docs it also allows to send binary files.
So I am trying to test this like that:
def test_buf():
import csv
import io
test_data = [[1, 2, 3], ["a", "b", "c"]]
# csv module can write data in io.StringIO buffer only
s = io.StringIO()
csv.writer(s).writerows(test_data)
s.seek(0)
# python-telegram-bot library can send files only from io.BytesIO buffer
# we need to convert StringIO to BytesIO
buf = io.BytesIO()
# extract csv-string, convert it to bytes and write to buffer
buf.write(s.getvalue().encode())
buf.seek(0)
# set a filename with file's extension
buf.name = 'test_data.csv'
return buf
And then
csv_output = test_buf()
bot.send_document(chat_id, csv_output, caption='Caption_text')
And I get an error:
"ApiTelegramException occurred, args=("A request to the Telegram API was unsuccessful. Error code: 400 Description: Bad Request: can't parse entities: Can't find end of the entity starting at byte offset 7",)
What do i do wrong? Maybe I don't fully understand difference between BytesIO and binary format? If it's different how to transform bytesio to binary in-memory so i could send data
For now I can send file but without telebot library:
requests.post(f'https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendDocument',
data={"chat_id": chat_id, "caption": 'caption_text'},
files={'document': csv_output})
So I do not understand what an issue with library. It like I sure that I just don't understand some basic stuff.

How to play mp3 from URL

I'm trying to write a python script that will play mp3 from Soundcloud URL
This is what I've already done:
from urllib.request import urlopen
url = "soundcloud.com/artist/song.mp3"
u = urlopen(url)
data = u.read(1024)
while data:
player.play(data)
data = u.read(1024)
I tried pyaudio with many options like changing formats, channels, rate.
and I just get strange sound from the speakers, I searched Google for pyaudio playing mp3 and didn't found any information.
I tried pygame by creating Sound object by passing the bytes from the mp3 and then just by executing the play function. I am not getting any errors: the script runs but nothing is playing.
I'm working with Python 3 and Ubuntu.
If you happen to have VLC installed (or are willing to install it), then this should work:
import vlc
p = vlc.MediaPlayer("http://your_mp3_url")
p.play()
This has the advantage that it works with everything VLC works with, not just MP3. It can also be paused if you want to.
You can install vlc for python using
pip install python-vlc
Check if you can download file manually using that URL. If its protected site with username/passwd, you may need to take care of that first.
If not, here is a working code that downloads file from url using urllib2 and then plays it using pydub.
Its a two step process where first mp3 file is downloaded and saved to file and then played using external player.
import urllib2
from pydub import AudioSegment
from pydub.playback import play
mp3file = urllib2.urlopen("http://www.bensound.org/bensound-music/bensound-dubstep.mp3")
with open('./test.mp3','wb') as output:
output.write(mp3file.read())
song = AudioSegment.from_mp3("./test.mp3")
play(song)
** Update **
You did mention that you need streaming from web. In that case you may want to look at GStreamer with Python Bindings
Here is a SO link for that.
Sorry but I do not have Python3 to test here, to stream mp3 using pyaudio you will need decode it in PCM data, I know that pymedia can do it, but it is too old and just support python27.
To do this the right way you will need to know some attributes of your audio, things like samplerate, number of channels, bit resolution, to set it in the pyaudio.
I can show how I do it using python27 + pyaudio, first I will show how it is done to stream .wav
from urllib2 import urlopen
#to python3.x
#from urllib.request import urlopen
import pyaudio
pyaud = pyaudio.PyAudio()
srate=44100
stream = pyaud.open(format = pyaud.get_format_from_width(1),
channels = 1,
rate = srate,
output = True)
url = "http://download.wavetlan.com/SVV/Media/HTTP/WAV/NeroSoundTrax/NeroSoundTrax_test4_PCM_Mono_VBR_8SS_44100Hz.wav"
u = urlopen(url)
data = u.read(8192)
while data:
stream.write(data)
data = u.read(8192)
choose large buffer, python is slow in while loop, i did it using chunks of size 8192, note that format, channels and rate are the rigth attributes for this wav file, so for .wav we not need decode, it is a PCM data, now for mp3 we will need decode and put in PCM format to stream.
Lets try using pymedia
from urllib2 import urlopen
import pyaudio
import pymedia.audio.acodec as acodec
import pymedia.muxer as muxer
dm= muxer.Demuxer( 'mp3' )
pyaud = pyaudio.PyAudio()
srate=44100
stream = pyaud.open(format = pyaud.get_format_from_width(2),
channels = 1,
rate = srate,
output = True)
url = "http://www.bensound.org/bensound-music/bensound-dubstep.mp3"
u = urlopen(url)
data = u.read(8192)
while data:
#Start Decode using pymedia
dec= None
s= " "
sinal=[]
while len( s ):
s= data
if len( s ):
frames= dm.parse( s )
for fr in frames:
if dec== None:
# Open decoder
dec= acodec.Decoder( dm.streams[ 0 ] )
r= dec.decode( fr[ 1 ] )
if r and r.data:
din = r.data;
s=""
#decode ended
stream.write(din)
data = u.read(8192)
This may be secret, because I never saw anyone showing how this can be done in python, for python3 I not know anything that can decode .mp3 into pieces like pymedia do.
Here these two codes are streming and working for .wav and .mp3

How to record twitch stream in python, preferably using livestreamer?

Currently all I have is:
from livestreamer import Livestreamer
session = Livestreamer()
stream = session.streams('http://www.twitch.tv/riotgames')
stream = stream['source']
fd = stream.open()
As I'm still a newbie to python I'm at complete loss on what I should do next. How do I continuously save, let's say, last 40 seconds of the stream to file?
Here's a start:
from livestreamer import Livestreamer
session = Livestreamer()
stream = session.streams('http://www.twitch.tv/riotgames')
stream = stream['source']
fd = stream.open()
with open("/tmp/stream.dat", 'wb') as f:
while True:
data = fd.read(1024)
f.write(data)
I've tried it. You can open the /tmp/stream.dat in VLC, for example. The example will read 1 kb at a time and write it to a file.
The program will run forever so you have to interrupt it with Ctrl-C, or add some logic for that. You probably need to handle errors and the end of a stream somehow.

Make a request to download a video in Python

I have links of the form:
http://youtubeinmp3.com/fetch/?video=LINK_TO_YOUTUBE_VIDEO_HERE
If you put links of this type in an <a> tag on a webpage, clicking them will download an MP3 of the youtube video at the end of the link. Source is here.
I'd like to mimic this process from the command-line by making post requests (or something of that sort), but I'm not sure how to do it in Python! Can I get any advice, please, or is this more difficult than I'm making it out to be?
As Mark Ma mentioned, you can get it done without leaving the standard library by utilizing urllib2. I like to use Requests, so I cooked this up:
import os
import requests
dump_directory = os.path.join(os.getcwd(), 'mp3')
os.makedirs(dump_directory, exist_ok=True)
def dump_mp3_for(resource):
payload = {
'api': 'advanced',
'format': 'JSON',
'video': resource
}
initial_request = requests.get('http://youtubeinmp3.com/fetch/', params=payload)
if initial_request.status_code == 200: # good to go
download_mp3_at(initial_request)
def download_mp3_at(initial_request):
j = initial_request.json()
filename = '{0}.mp3'.format(j['title'])
r = requests.get(j['link'], stream=True)
with open(os.path.join(dump_directory, filename), 'wb') as f:
print('Dumping "{0}"...'.format(filename))
for chunk in r.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
f.flush()
It's then trivial to iterate over a list of YouTube video links and pass them into dump_mp3_for() one-by-one.
for video in ['http://www.youtube.com/watch?v=i62Zjga8JOM']:
dump_mp3_for(video)
In its API Doc, it provides one version of URL which returns download link as JSON: http://youtubeinmp3.com/fetch/?api=advanced&format=JSON&video=http://www.youtube.com/watch?v=i62Zjga8JOM
Ok Then we can use urllib2 to call the API and fetch API result, then unserialize with json.loads(), and download mp3 file using urllib2 again.
import urllib2
import json
r = urllib2.urlopen('http://youtubeinmp3.com/fetch/?api=advanced&format=JSON&video=http://www.youtube.com/watch?v=i62Zjga8JOM')
content = r.read()
# extract download link
download_url = json.loads(content)['link']
download_content = urllib2.urlopen(download_url).read()
# save downloaded content to file
f = open('test.mp3', 'wb')
f.write(download_content)
f.close()
Notice the file should be opened using mode 'wb', otherwise the mp3 file cannot be played correctly.
If the file is big, downloading will be a time-consuming progress. And here is a post describes how to display downloading progress in GUI (PySide)
If you want to download video or just the audio from YouTube you can use this module pytube it does all the hard work.
You can also list the audio only:
from pytube import YouTube
# initialize a YouTube object by the url
yt = YouTube("YOUTUBE_URL")
# that will get all audio files available
audio_list = yt.streams.filter(only_audio=True).all()
print(audio_list)
And then download it:
# that will download the file to current working directory
yt.streams.filter(only_audio=True)[0].download()
Complete Code:
from pytube import YouTube
yt = YouTube ("YOUTUBE_URL")
audio = yt.streams.filter(only_audio=True).first()
audio.download()

MP3 with Pyaudio

import pyaudio
import wave
chunk = 1024
wf = wave.open('yes.mp3', 'rb')
p = pyaudio.PyAudio()
stream = p.open(
format = p.get_format_from_width(wf.getsampwidth()),
channels = wf.getnchannels(),
rate = wf.getframerate(),
output = True)
data = wf.readframes(chunk)
while data != '':
stream.write(data)
data = wf.readframes(chunk)
stream.close()
p.terminate()
No matter how I put this, while trying multiple methods I seem to keep getting the following error in terminal:
raise Error, 'file does not start with RIFF id'
I would use pyglet but media and all other modules aren't detected even though I'm able to import pyglet.
Any help?
You're using wave to attempt to open a file that is not wav. Instead, you're attempting to open an mp3 file. The wave module can only open wav files, so you need to convert the mp3 to wav. Here's how you can use pyglet to play an mp3 file:
import pyglet
music = pyglet.resource.media('music.mp3')
music.play()
pyglet.app.run()
It would be much simpler than the method you're trying. What errors are you getting with pyglet?

Categories