text: #!/usr/bin/env python
  # coding: utf-8
  
  import base64
  import itertools
  
  import mutagen.ogg
  import mutagen.oggvorbis
  import mutagen.oggopus
  import mutagen.oggflac
  import mutagen.oggtheora
  import mutagen.oggspeex
  
  from music_tag import util
  from music_tag.file import Artwork, AudioFile, MetadataItem, TAG_MAP_ENTRY
  
  
  def get_pictures(afile, norm_key):
      artworks = []
  
      pics_dat = afile.mfile.get("coverart", [])
      mimes = afile.mfile.get("coverartmime", [])
      for dat, mime in itertools.zip_longest(pics_dat, mimes, fillvalue=""):
          image_data = base64.b64decode(dat.encode("ascii"))
          artworks = Artwork(image_data)
  
      for p in afile.mfile.tags['metadata_block_picture']:
          pb = util.parse_picture_block(base64.standard_b64decode(p))
          art = Artwork(pb.data, width=pb.width, height=pb.height, fmt=pb.format)
          artworks.append(art)
  
      return MetadataItem(Artwork, None, artworks)
  
  def set_pictures(afile, norm_key, artworks):
      if not isinstance(artworks, MetadataItem):
          raise TypeError()
  
      pics = []
      for i, art in enumerate(artworks.values):
          if any(v is None for v in (art.mime, art.width, art.height, art.depth)):
              raise ImportError("Please install Pillow to properly handle images")
          pic = mutagen.flac.Picture()
          pic.data = art.raw
          pic.type = art.pic_type
          pic.mime = art.mime
          pic.width = art.width
          pic.height = art.height
          pic.depth = art.depth
  
          pic_data = base64.b64encode(pic.write()).decode('ascii')
          pics.append(pic_data)
      afile.mfile.tags['metadata_block_picture'] = pics
  
  def rm_pictures(afile, norm_key):
      for k in ('coverart', 'coverartmime', 'metadata_block_picture'):
          if k in afile.mfile.tags:
              del afile.mfile.tags[k]
  
  
  class OggFile(AudioFile):
      tag_format = "Ogg"
      mutagen_kls = mutagen.ogg.OggFileType
  
      _TAG_MAP = {
          'tracktitle': TAG_MAP_ENTRY(getter='title', setter='title', type=str),
          'artist': TAG_MAP_ENTRY(getter='artist', setter='artist', type=str),
          'album': TAG_MAP_ENTRY(getter='album', setter='album', type=str),
          'albumartist': TAG_MAP_ENTRY(getter='albumartist', setter='albumartist',
                                       type=str),
          'composer': TAG_MAP_ENTRY(getter='composer', setter='composer', type=str),
          'tracknumber': TAG_MAP_ENTRY(getter='tracknumber', setter='tracknumber',
                                       type=int),
          'totaltracks': TAG_MAP_ENTRY(getter='tracktotal', setter='tracktotal',
                                       type=int),
          'discnumber': TAG_MAP_ENTRY(getter='discnumber', setter='discnumber',
                                      type=int),
          'totaldiscs': TAG_MAP_ENTRY(getter='disctotal', setter='disctotal',
                                      type=int),
          'genre': TAG_MAP_ENTRY(getter='genre', setter='genre', type=str),
          'year': TAG_MAP_ENTRY(getter=('date', 'originaldate'),
                                setter=('date', 'originaldate'),
                                type=int, sanitizer=util.sanitize_year),
          'lyrics': TAG_MAP_ENTRY(getter='lyrics', setter='lyrics', type=str),
          'isrc': TAG_MAP_ENTRY(getter='isrc', setter='isrc', type=str),
          'comment': TAG_MAP_ENTRY(getter='comment', setter='comment', type=str),
          'compilation': TAG_MAP_ENTRY(getter='compilation', setter='compilation',
                                       type=int, sanitizer=util.sanitize_bool),
  
          'artwork': TAG_MAP_ENTRY(getter=get_pictures, setter=set_pictures,
                                   remover=rm_pictures,
                                   type=Artwork),
      }
  
      def _ft_setter(self, key, md_val, appendable=True):
          if self.appendable and appendable:
              self.mfile.tags[key] = [str(v) for v in md_val.values]
          else:
              self.mfile.tags[key] = str(md_val.value)
  
  
  class OggFlacFile(OggFile):
      tag_format = "OggFlac"
      mutagen_kls = mutagen.oggflac.OggFLAC
  
  
  class OggSpeexFile(OggFile):
      tag_format = "OggSpeex"
      mutagen_kls = mutagen.oggspeex.OggSpeex
  
  
  class OggTheoraFile(OggFile):
      tag_format = "OggTheora"
      mutagen_kls = mutagen.oggtheora.OggTheora
  
  
  class OggVorbisFile(OggFile):
      tag_format = "OggVorbis"
      mutagen_kls = mutagen.oggvorbis.OggVorbis
  
      _TAG_MAP = OggFile._TAG_MAP.copy()
      _TAG_MAP.update({
          '#codec': TAG_MAP_ENTRY(getter=lambda afile, norm_key: 'Ogg Vorbis',
                                  type=str),
          '#bitspersample': TAG_MAP_ENTRY(getter=lambda afile, norm_key: None,
                                  type=int),
      })
  
  
  class OggOpusFile(OggFile):
      tag_format = "OggOpus"
      mutagen_kls = mutagen.oggopus.OggOpus
  
      _TAG_MAP = OggFile._TAG_MAP.copy()
      _TAG_MAP.update({
          '#codec': TAG_MAP_ENTRY(getter=lambda afile, norm_key: 'Ogg Opus',
                                  type=str),
          '#bitspersample': TAG_MAP_ENTRY(getter=lambda afile, norm_key: None,
                                  type=int),
          '#samplerate': TAG_MAP_ENTRY(getter=lambda afile, norm_key: None,
                                       type=int),
          '#bitrate': TAG_MAP_ENTRY(getter=lambda afile, norm_key: None,
                                    type=int),
      })
  