beetbox / beets

music library manager and MusicBrainz tagger
http://beets.io/
MIT License
12.91k stars 1.82k forks source link

Plugin to generate NFO files, especially for Kodi #2413

Open OmgImAlexis opened 7 years ago

OmgImAlexis commented 7 years ago

It'd be great to see an option for NFO files being written for artists and albums which would mean the MBID can be saved as well as other details. This helps with things like KODI, Plex, etc. and would also help with beets and updating music libraries even if the database file is deleted.

For an example of the NFO files have a look at what KODI accepts. Most other platforms that use NFO files for music either use the same format as KODI or an extended format which uses KODI's as a base.

http://kodi.wiki/view/NFO_files/Music http://kodi.wiki/view/Music_tagging (go down to "6 NFO files")

akyag commented 7 years ago

+1000000000000 And there is no other software which can do this for music. And maybe in the future artist artwork, thumbs, backgrounds from https://fanart.tv/music-fanart/ for ex. can be fetched too?

ghost commented 7 years ago

@akyag: there's already a fanart.tv backend for the fetchart plugin, so that part is done

ghost commented 7 years ago

@akyag : sorry, i thought we did have fanart.tv already, but this implies not so https://github.com/beetbox/beets/issues/889

sampsyo commented 7 years ago

Ah, so these are little XML files containing metadata? Seems like a fine request.

tigranl commented 7 years ago

Hi, @sampsyo! Where can we store .nfo files? I think I can implement this feature.

sampsyo commented 7 years ago

Cool! I actually don't know where Kodi expects them to be... perhaps in the album directory (album.path in beets)?

tigranl commented 7 years ago

Another one question. I assume it should be a plugin?

sampsyo commented 7 years ago

Yeah, totally—integrations with specific other software count as narrow enough use cases that they should be plugins.

bajosoto commented 7 years ago

Hi @tigranl. I'm also interested in implementing this feature. If you have already started something in a repo would you mind sharing so maybe we can collaborate on this? Also, do you think this kind of feature would be more useful as a CLI command, or as part of the importing process?

bajosoto commented 7 years ago

And to your question, it's two kinds of file. artist.nfo goes in the artist folder and album.nfo in the album one. Also, according to the wiki, "Both album.nfo and artist.nfo files can contain the MusicBrainz tag or simply contain a URL to the correct page on the MusicBrainz website". Maybe this would be a much simpler approach than generating the xml structure?

tigranl commented 7 years ago

@bajosoto I just started, I'll make a PR soon. I think it would be more appropriate as part of the importing process.

tigranl commented 7 years ago

Yeah, using just a URL would simplify everything.

bajosoto commented 7 years ago

Ok, thanks. I have a very, very simple and rough (but working!) implementation of a plugin here that generates the .nfo file for albums (no artists yet) as part of the import process like you mentioned. I am aware I'm doing a second call to music brainz that could (and should) be spared since this is already part of the import process, but I'm not quite sure of how can I pull the data that is already in the task in commands.py (the url is already fetched there) all the way into my plugin. It's probably a silly question, but I'm a beginner with python and any input or feedback would be much appreciated. :D

sampsyo commented 7 years ago

Cool, thanks for getting this started!

It's actually pretty simple to get the ID out of the album object. You can just use album.mb_albumid to get the MBID that has been assigned to the album after matching.

If you're curious about the full set of fields that are available on album, it's here.

bajosoto commented 7 years ago

How did I miss that..? Thanks @sampsyo. I'll improve it tomorrow :bowtie:

tigranl commented 7 years ago

It might be a good idea to use 'import' event, so it will work with singletones as well.

akyag commented 7 years ago

how would it work for singletons? one nfo for every single track?

tigranl commented 7 years ago

Yep.

tigranl commented 7 years ago

https://gist.github.com/tigranl/79652e7dfac1d6216c1c0a2d0bbf696f

bajosoto commented 7 years ago

Hey @tigranl, from what I see in the KODI wiki, there seems to be no template for singletons so these would probably not be recognized by it (perhaps this works in Plex or others?). Nevertheless they can be generated. I believe using the item_imported event would be a good idea, alongside album_import since it's not called during album imports from what I understand from the documentation. @sampsyo, is there any way to fetch the album artist path from within the plugin based on the path configuration?

sampsyo commented 7 years ago

There's no specific album associated with each album artist. However, you might try using the parent directory of the album, which is likely to work with most (but not all) path configurations.

bajosoto commented 7 years ago

Yeah, that's what I was thinking. I guess it wouldn't work for certain configurations.. Thanks!

peace899 commented 7 years ago

I have been thinking about creating .nfo files for kodi using beets data but unfortunately I'm not clued up on databases and python. But I made headway by creating a bash script. Found here

peace899 commented 7 years ago

With my limited python knowledge and lots of googling, I came up with this script. Obviously would like to turn it into a plugin (or run it with runafter.py plugin, any help welcome!

peace899 commented 7 years ago

RE: artist path I have made this attempt to get artist path from the config file. Probably might work for most configurations with $albumartist in default path:

import os, re
import beets.library
from beets import config
from pathlib import Path

libpath = os.path.expanduser(str(config['library']))
lib = beets.library.Library(libpath)
mb_albumid = 'e26afcc2-7ef9-49e9-b64f-8f74a5ff15c3' #example mbid
albumid = 'mb_albumid:'+ mb_albumid

def artist_path(albumid):
    for album in lib.albums(albumid):
        albumpath = album.path.decode("utf-8")
        root = str(config['directory'])
        folder = os.path.join(root, str(config['paths']['default']))
        config_items = Path(folder).parts
        folder_length = len(config_items)
        indices = [i for i, s in enumerate(config_items) if 'albumartist' in s]
        y = int(folder_length - indices[0])
        artistpath_items = list(Path(albumpath).parts[-y:-1])
        artist_path = os.path.join(root, *artistpath_items)
        return artist_path