# What are my options for storing "play\_count" in MediaFile?

**URL:** <https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188>\
**Category:** Help\
**Created:** [March 31, 2020, 7:09pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188 "2020-03-31T19:09:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jakabadambalazs](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/jakabadambalazs/32/360_2.png) [@jakabadambalazs](https://discourse.beets.io/u/jakabadambalazs)\
**Post date:** [March 31, 2020, 7:09pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/1 "2020-03-31T19:09:14Z")

</div>

Hi,

I am storing a “play\_count” flex attribute in the db for one of my plugins. I would also like to optionally write this attribute to the MediaFile.

I tried this:

```python
item.try_write(tags={"play_count": play_count})

```

but no avail.  
Any tips?

---

<div class="post-metadata">

**Author:** ![jakabadambalazs](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/jakabadambalazs/32/360_2.png) [@jakabadambalazs](https://discourse.beets.io/u/jakabadambalazs)\
**Post date:** [March 31, 2020, 8:51pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/2 "2020-03-31T20:51:58Z")

</div>

I think I got it:

I registered a listener for the “after\_write” event with this method:

```python
def write_play_count_to_mediafile(item: Item, path: str):
    play_count_fld = MediaField(MP3DescStorageStyle(desc="play_count"))
    mf = MediaFile(path)
    mf.add_field("play_count", play_count_fld)
    setattr(mf, "play_count", str(item.get("play_count", 0)))
    mf.save()

```

and it works… Incredible!!! 🤩

So, I change my question: Which event would you use for reading and adding the same attribute to the item on import? The `item_imported` event or would it be better to work with a [non-blocking pipeline stage](https://beets.readthedocs.io/en/stable/dev/plugins.html#add-import-pipeline-stages)?

---

<div class="post-metadata">

**Author:** ![adrian](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/adrian/32/4_2.png) [@adrian](https://discourse.beets.io/u/adrian)\
**Post date:** [March 31, 2020, 8:56pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/3 "2020-03-31T20:56:11Z")

</div>

Yo! For that, you’ll need to add a field to MediaFile that describes the mapping to actual metadata tags:  
[https://beets.readthedocs.io/en/stable/dev/plugins.html#extend-mediafile](https://beets.readthedocs.io/en/stable/dev/plugins.html#extend-mediafile)

---

<div class="post-metadata">

**Author:** ![adrian](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/adrian/32/4_2.png) [@adrian](https://discourse.beets.io/u/adrian)\
**Post date:** [March 31, 2020, 8:58pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/4 "2020-03-31T20:58:57Z")

</div>

Aha! Oops, looks like I was too slow. 😃 🤦‍♂️

If I were you, I’d add the MediaField when your plugin loads up. Then it’s permanently available to all stages of beets. Then you don’t need an explicit `save`—anything that writes tags will automatically get the `play_count` value from the database.

If you don’t want that (if you don’t want `play_count` to be in the database, for example), probably a pipeline stage. That way, the latency of the file operation will be overlapped with other actions. But it’s likely not to be too slow, so it won’t matter too much.

---

<div class="post-metadata">

**Author:** ![jakabadambalazs](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/jakabadambalazs/32/360_2.png) [@jakabadambalazs](https://discourse.beets.io/u/jakabadambalazs)\
**Post date:** [March 31, 2020, 9:16pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/5 "2020-03-31T21:16:14Z")

</div>

Thanks for the tip! Maybe I will read the manual 📖 next time before asking questions already answered there ;), 😊 sorry.

---

<div class="post-metadata">

**Author:** ![jakabadambalazs](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/jakabadambalazs/32/360_2.png) [@jakabadambalazs](https://discourse.beets.io/u/jakabadambalazs)\
**Post date:** [April 1, 2020, 7:00am UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/6 "2020-04-01T07:00:57Z")

</div>

Supercool! Extending the MediaFile works great. Just one question (or two). I don’t understand why the guide says to initialise the MediaField this way:

```python
field = mediafile.MediaField(
            mediafile.MP3DescStorageStyle(u'foo'),
            mediafile.StorageStyle(u'foo')
        )

```

Why to I need the second ‘generic’ style in the constructor?

I also added the `out_type` to so my code looks like this:

```python
# Add `play_count` field support
        fld_name = u'play_count'
        field = mediafile.MediaField(
            mediafile.MP3DescStorageStyle(fld_name),
            mediafile.StorageStyle(fld_name),
            out_type=int
        )
        self.add_media_field(fld_name, field)

```

With this I hoped to be able to remove the following from my plugin

```python
    @property
    def item_types(self):
        return {'play_count': types.INTEGER}

```

but without it I get the following error when trying to to numeric operations on the field:

```python
    play_count = item.get("play_count", 0) + 1
TypeError: can only concatenate str (not "int") to str

```

So the `out_type=int` on the MediaField has nothing to do with the type of the field on the library Item?

---

<div class="post-metadata">

**Author:** ![adrian](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/adrian/32/4_2.png) [@adrian](https://discourse.beets.io/u/adrian)\
**Post date:** [April 1, 2020, 2:24pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/7 "2020-04-01T14:24:54Z")

</div>

Great; glad this is working!

> [@jakabadambalazs](#):
>
> Why to I need the second ‘generic’ style in the constructor?

The latter style is for file formats that use key/value tag data—FLAC, Ogg Vorbis, etc. They need a different mapping from ID3 tags, which use a complicated “frame” system, and other more structured formats like MPEG-4 and Windows Media.

> [@jakabadambalazs](#):
>
> So the `out_type=int` on the MediaField has nothing to do with the type of the field on the library Item?

Indeed—MediaFile is mostly decoupled from beets itself, so the types it declares are different from the beets type system. In particular, MediaFile `out_type` conversions are plain Python types, while beets types are much richer (they can express padding, date formats, etc.).

---

<div class="post-metadata">

**Author:** ![jakabadambalazs](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.beets.io/jakabadambalazs/32/360_2.png) [@jakabadambalazs](https://discourse.beets.io/u/jakabadambalazs)\
**Post date:** [April 1, 2020, 2:46pm UTC](https://discourse.beets.io/t/what-are-my-options-for-storing-play-count-in-mediafile/1188/8 "2020-04-01T14:46:44Z")

</div>

Thanks a lot for the info.
