pythonbitrate

Find bitrate of an audio file on a website without downloading the file


I want to find the bitrate of an mp3 on a website without downloading the file. Using Python3 & Mutagen Ported Version

Code

from mutagen.id3 import ID3
audio = ID3("http://songs.djmazadownload.com/music/indian_movies/Creature%20(2014)/01%20-%20Creature%20-%20Sawan%20Aaya%20Hai%20%5BDJMaza.Info%5D.mp3")
print (audio.info.length, audio.info.bitrate)

Error

Traceback (most recent call last):
  File "C:\Python_Mass_downloader\New folder\download.py", line 20, in <module>
    audio = ID3("http://songs.djmazadownload.com/music/indian_movies/Creature%20(2014)/01%20-%20Creature%20-%20Sawan%20Aaya%20Hai%20%5BDJMaza.Info%5D.mp3")
  File "C:\Python34\lib\site-packages\mutagen\id3.py", line 76, in __init__
    super(ID3, self).__init__(*args, **kwargs)
  File "C:\Python34\lib\site-packages\mutagen\_util.py", line 41, in __init__
    super(DictProxy, self).__init__(*args, **kwargs)
  File "C:\Python34\lib\site-packages\mutagen\__init__.py", line 46, in __init__
    self.load(*args, **kwargs)
  File "C:\Python34\lib\site-packages\mutagen\id3.py", line 122, in load
    self._fileobj = open(filename, 'rb')
OSError: [Errno 22] Invalid argument: 'http://songs.djmazadownload.com/music/indian_movies/Creature%20(2014)/01%20-%20Creature%20-%20Sawan%20Aaya%20Hai%20%5BDJMaza.Info%5D.mp3'

Sample Input

http://songs.djmazadownload.com/music/indian_movies/Creature%20%282014%29/01%20-%20Creature%20-%20Sawan%20Aaya%20Hai%20%5BDJMaza.Info%5D.mp3

Any other ways are also welcome :) Thank You


Solution

  • First:

    I Dont want to download the files . I just need to check from the server . I also want to Find image's (jpg,png etc) information like size , pixels . Is it posssible ?

    No, it's not possible. The only way to get that information is by parsing the file data, and you can't parse the file data unless you download the file data.

    Of course if the server provides that information in some other way, like via a REST or RPC API, or a web page you can scrape, then you can download the information… but in that case, you're not parsing the file yourself, and you have no need for Mutagen. (And if you control the server, you can always add a web app that does the parsing on the server side and provides the information in any format you want.)


    If you're just worried about saving the file to disk: Whether from the stdlib or from third-party modules, most functions in Python that want a filename cannot take a network URL. That's different from some other languages, which take URLs everywhere and try to treat http and file URLs the same way whenever possible (by downloading the file chunk by chunk into memory).

    However, most functions that want a file object can take a urlrequest or similar object, and, if they can't, can usually take a BytesIO. So, you don't need to download it to a file on disk:

    import urllib.request
    
    r = urllib.request.open(url)
    spam(r)
    

    The problem is, I don't think Mutagen's "simple API" functions like ID3 can take file objects, only filenames. So, you will have to either use a different library, use lower-level functions,* or download to a temporary file.

    But even that last one isn't so terrible:

    import tempfile
    import urllib.request
    
    r = urllib.request.open(url)
    with tempfile.NamedTemporaryFile(mode='wb', delete=False) as f:
        f.write(r.read())
    try:
        id3 = mutagen.id3.ID3(f.name)
    finally:
        os.remove(f.name)
    

    Or, if you don't care about Windows, you can simplify that to:

    r = urllib.request.open(url)
    with tempfile.NamedTemporaryFile(mode='wb') as f:
        f.write(r.read())
        f.flush()
        id3 = mutagen.id3.ID3(f.name)
    

    NamedTemporaryFile creates and opens a temporary file. By default, it will be deleted as soon as you close it (which happens as soon as the with statement ends). The problem with using it that way is that on Windows, ID3 may not be able to open the temporary file until you close it, which means you have to pass delete=False to the constructor, and then explicitly os.remove it later. Clumsy, but the best way I know of to write it in a way that's safe and robust for all platforms. (Again, if you don't care about Windows, just use the simpler second version.)

    If you don't understand the with statement, PEP 343 probably explains it best, but oversimplifying a bit, the idea is that runs all the indented code, then automatically closes the file (even if you return or raise an exception in the middle of the indented code).


    One of the few things you can get from an HTTP server is the size of a file. Servers usually send a Content-Length: header for every response, and if you send a HEAD request instead of a GET, you get just the headers, not all the data. So:

    >>> req = urllib.request.Request(url, method='HEAD')
    >>> resp = urllib.request.urlopen(req)
    >>> size = int(resp.headers['Content-Length'])
    6201098
    

    * In fact, I'm not even sure "use lower-level functions" is an option; I can't remember for sure, but I think being able to use open file objects or strings in place of filenames was something that MusicBrainz had to add to their fork of Mutagen because there was no way to do it.