# Buggy code
def ParsePLS(file):
    data = {}

    lines = file.readlines()
    if not lines or "[playlist]" not in lines.pop(0):
        return []

    for line in lines:
        try:
            head, val = line.strip().split("=", 1)
        except (TypeError, ValueError):
            continue
        else:
            head = head.lower()
            if head.startswith("length") and val == "-1":
                continue
            else:
                data[head] = val.decode("utf-8", "replace")

    count = 1
    files = []
    warnings = []
    while True:
        if "file%d" % count in data:
            filename = data["file%d" % count].encode("utf-8", "replace")
            if filename.lower()[-4:] in [".pls", ".m3u"]:
                warnings.append(filename)
            else:
                irf = IRFile(filename)
                for key in ["title", "genre", "artist"]:
                    try:
                        irf[key] = data["%s%d" % (key, count)]
                    except KeyError:
                        pass
                try:
                    irf["~#length"] = int(data["length%d" % count])
                except (KeyError, TypeError, ValueError):
                    pass
                files.append(irf)
        else:
            break
        count += 1

    if warnings:
        qltk.WarningMessage(
            None,
            _("Unsupported file type"),
            _(
                "Station lists can only contain locations of stations, "
                "not other station lists or playlists. The following locations "
                "cannot be loaded:\n%s"
            )
            % "\n  ".join(map(util.escape, warnings)),
        ).run()

    return files


# Traceback (TypeError)
=== SYSTEM INFORMATION:
Quod Libet 3.6.2
Mutagen 1.31
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] linux2
Platform Linux-4.4.0-24-generic-x86_64-with-Ubuntu-16.04-xenial

=== STACK TRACE
Traceback (most recent call last):

File "/usr/lib/python2.7/dist-packages/quodlibet/browsers/iradio.py", line 803, in __add
self.__add_station(uri)

File "/usr/lib/python2.7/dist-packages/quodlibet/browsers/iradio.py", line 806, in __add_station
irfs = add_station(uri)

File "/usr/lib/python2.7/dist-packages/quodlibet/browsers/iradio.py", line 213, in add_station
err = e.strerror[1].decode(encoding, 'replace')

TypeError: 'NoneType' object has no attribute '__getitem__'


=== LOG:
D: 991.28: PlaylistMux.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd258 (GtkTreeIter at 0x7f1f200bd0e0)>
D: 991.28: QueueModel.go_to: Told to go to None
D: 991.28: PlaylistModel.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd258 (GtkTreeIter at 0x7f1f200bd0e0)>
D: 991.28: GStreamerPlayer._end: End song
D: 991.28: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 991.29: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 991.29: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 991.29: GStreamerPlayer._end: Next song
D: 991.39: SongLibrary._changed: Changing 2 items.
D: 991.39: qltk.completion.__update_song: Updating tag model for 2 songs
D: 991.39: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 992.07: player.gstbe.player.__message: Recalculate latency
D: 992.07: SongLibrary._changed: Changing 1 items.
D: 992.07: qltk.completion.__update_song: Updating tag model for 1 songs
D: 992.07: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 996.70: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 996.70: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 996.70: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 996.71: SongLibrary._changed: Changing 1 items.
D: 996.71: qltk.completion.__update_song: Updating tag model for 1 songs
D: 996.71: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 039.71: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 039.71: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 039.71: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 039.80: SongLibrary._changed: Changing 2 items.
D: 039.80: qltk.completion.__update_song: Updating tag model for 2 songs
D: 039.80: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 171.42: GStreamerPlayer.go_to: Going to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1f6400a560)>
D: 171.42: PlaylistMux.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1f6400a560)>
D: 171.42: QueueModel.go_to: Told to go to None
D: 171.42: PlaylistModel.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1f6400a560)>
D: 171.43: GStreamerPlayer._end: End song
D: 171.43: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 171.43: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 171.43: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 171.43: GStreamerPlayer._end: Next song
W: Could not resolve server name
W: Error resolving 'pub3.di.fm': Name or service not known (2), URL: http://pub3.di.fm:80/di_chillstep_aac, Redirect to: (NULL)
D: 171.74: SongLibrary._changed: Changing 2 items.
D: 171.74: qltk.completion.__update_song: Updating tag model for 2 songs
D: 171.74: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 175.50: GStreamerPlayer.go_to: Going to <Gtk.TreeIter object at 0x7f1efc8d9ef0 (GtkTreeIter at 0x7f1f2001df20)>
D: 175.50: PlaylistMux.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8d9ef0 (GtkTreeIter at 0x7f1f2001df20)>
D: 175.50: QueueModel.go_to: Told to go to None
D: 175.50: PlaylistModel.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8d9ef0 (GtkTreeIter at 0x7f1f2001df20)>
D: 175.50: GStreamerPlayer._end: End song
D: 175.50: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 175.50: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 175.50: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 175.51: GStreamerPlayer._end: Next song
D: 175.55: SongLibrary._changed: Changing 1 items.
D: 175.56: qltk.completion.__update_song: Updating tag model for 1 songs
D: 175.56: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 185.59: GStreamerPlayer.go_to: Going to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1ee800d8c0)>
D: 185.59: PlaylistMux.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1ee800d8c0)>
D: 185.59: QueueModel.go_to: Told to go to None
D: 185.59: PlaylistModel.go_to: Told to go to <Gtk.TreeIter object at 0x7f1efc8bd460 (GtkTreeIter at 0x7f1ee800d8c0)>
D: 185.59: GStreamerPlayer._end: End song
D: 185.59: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 185.59: util.cover.manager.failure: Didn't get cover from EmbedCover: This source is incapable of fetching covers
D: 185.59: util.cover.manager.failure: Didn't get cover from MusicBrainzCover: MBID is required to fetch the cover
D: 185.60: GStreamerPlayer._end: Next song
D: 185.66: SongLibrary._changed: Changing 1 items.
D: 185.67: qltk.completion.__update_song: Updating tag model for 1 songs
D: 185.67: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 204.15: config.save: Writing config...
D: 204.16: library.save: Saving all libraries...
D: 204.16: SongLibrary.save: Saving contents to '/home/CreamyCookie/.quodlibet/stations_all'.
D: 204.57: SongLibrary.save: Saving contents to '/home/CreamyCookie/.quodlibet/stations'.
W: A network error occurred, or the server closed the connection unexpectedly
W: Could not connect: Socket I/O timed out (7), URL: http://72.13.91.147, Redirect to: (NULL)
D: 278.08: PlaylistModel.set: Clearing model.
D: 278.08: PlaylistModel.set: Setting 48 songs.
D: 278.08: PlaylistModel.set: Done filling model.
D: 278.15: PlaylistModel.set: Clearing model.
D: 278.15: PlaylistModel.set: Setting 48 songs.
D: 278.15: PlaylistModel.set: Done filling model.

# Fixed code
def ParsePLS(file):
    data = {}

    lines = file.readlines()
    if not lines or "[playlist]" not in lines.pop(0):
        return []

    for line in lines:
        try:
            head, val = line.strip().split("=", 1)
        except (TypeError, ValueError):
            continue
        else:
            head = head.lower()
            if head.startswith("length") and val == "-1":
                continue
            else:
                data[head] = val.decode("utf-8", "replace")

    count = 1
    files = []
    warnings = []
    while True:
        if "file%d" % count in data:
            filename = data["file%d" % count].encode("utf-8", "replace")
            if filename.lower()[-4:] in [".pls", ".m3u"]:
                warnings.append(filename)
            else:
                irf = IRFile(filename)
                for key in ["title", "genre", "artist"]:
                    try:
                        irf[key] = data["%s%d" % (key, count)]
                    except KeyError:
                        pass
                try:
                    irf["~#length"] = int(data["length%d" % count])
                except (KeyError, TypeError, ValueError):
                    pass
                files.append(irf)
        else:
            break
        count += 1

    if warnings:
        WarningMessage(
            None,
            _("Unsupported file type"),
            _(
                "Station lists can only contain locations of stations, "
                "not other station lists or playlists. The following locations "
                "cannot be loaded:\n%s"
            )
            % "\n  ".join(map(util.escape, warnings)),
        ).run()

    return files