Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parentwork plugin #2580

Closed
wants to merge 191 commits into from
Closed

Add parentwork plugin #2580

wants to merge 191 commits into from

Conversation

dosoe
Copy link
Contributor

@dosoe dosoe commented May 31, 2017

Add a plugin that is able to fetch a performer, his sort name, the work, the work it is part of ( as explained in #2452 ) and the respective disambiguations, composer names and sort names.
This plugin doesn't work in its current form, I don't understand why (there is certainly a valuable reason and an easy fix, I'm just completely helpless when confronted with SQL).
I would be interested in additional featues or options for this plugin.

What it should do so far is:
fetch the performers of the recording
fetch the work title and disambiguation
look if the work is part of a bigger one, if yes take the work it is part of, repeat
fetch the parent work (which is part of no work) and disambiguation
fetch its composer (sort)name

Afaict the fetch part works fine, it's just the writing part that doesn't.
So far, I would only put the tags into the library, but if there is an actual tag out there where it can be written in the file itself I would be interested.

@dosoe

This comment has been minimized.

@dosoe

This comment has been minimized.

beetsplug/parentwork.py Outdated Show resolved Hide resolved
beetsplug/parentwork.py Outdated Show resolved Hide resolved
beets/library.py Outdated Show resolved Hide resolved
beetsplug/parentwork.py Show resolved Hide resolved
beetsplug/parentwork.py Outdated Show resolved Hide resolved
beetsplug/parentwork.py Outdated Show resolved Hide resolved
item['parent_composer'] = parent_composer
item['parent_composer_sort'] = parent_composer_sort

item.try_write()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're not planning on adding actual file tags for these fields, there's no need to call the write method.

dosoe added 3 commits June 1, 2017 14:25
Added flexible fields and corrected the typo of the tag: it was a
list before for each tag, now it is a string. Also cleaned up a bit,
but there is probably some whitespace to remove still or lines to break.
@dosoe

This comment has been minimized.

@dosoe

This comment has been minimized.

It seems that I should have lines shorter than 79 chars. However, I have
so many nested loops or tests that this is hardly possible
without removing the multiple tests for reaching the MB server.
Normally, when beets tries to fetch something from MB using musicbrainzngs
it has 8 tries and raises an error if it still doesn't work. However,
for me, 8 tries are usually not enough (it doesn't work about half the times
) so I added more tries. This will be discarded because it creates two
supplementary indentation blocks.
@dosoe

This comment has been minimized.

@dosoe

This comment has been minimized.

@dosoe

This comment has been minimized.

dosoe added 3 commits June 3, 2017 13:11
Put the search of the parentwork in a separate function, to allow
to make longer lines.
@dosoe

This comment has been minimized.

@dosoe

This comment has been minimized.

@dosoe
Copy link
Contributor Author

dosoe commented May 12, 2019

@sampsyo it seems like the tests are finally running fine. However, each time I want to edit the changelog I get a merging conflict, do you know why, or is it just that I didn't touch it for so long that I don't know how to use git anymore? Once this is cleared, could this be the moment to merge it?

Copy link
Member

@arcresu arcresu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating your changes!

Your PR is trying to add 191 commits to beets, which seems like rather a lot. Could you look into rebasing to squash some of your intermediate commits? Perhaps hidden by this is that you've changed the file mode on some unrelated scripts like extra/release.py, which doesn't seem intended.

We reorganised the changelog file recently and something related to that is resulting in a confusing diff where it looks like your PR is re-applying those changes rather than just adding a new line. Something doesn't look right with the changelog.

EDIT: I realise you and Adrian discussed the commit count earlier, but I think the current situation is not ideal at least for commits that touch core files in beets. Sometimes we need to dig through the history of a file to debug or port changes, and it's made more difficult when the commit history contains many intermediate commits.

item.track_alt = track_info.track_alt

# Miscellaneous/nullable metadata.
misc_fields = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: this seems like it should be 2 variables misc_album_fields and misc_item_fields rather than a dict.

MP4StorageStyle('----:com.apple.iTunes:Work'),
StorageStyle('WORK'),
ASFStorageStyle('beets/Work'),
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're planning to split MediaFile out into a standalone library so this addition will also need to be ported there. I can help with that if you like.

MP3DescStorageStyle(u'Work'),
MP4StorageStyle('----:com.apple.iTunes:Work'),
StorageStyle('WORK'),
ASFStorageStyle('beets/Work'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't want anything beets-specific in the storage style.


def find_parentwork(work_id):
"""This function gives the work relationships (dict) of a parent_work
given the id of the work"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring style used by beets needs the final """ to be on its own line.

classical music, just fetching the work title as in MusicBrainz is not
satisfying, because MusicBrainz has separate works for, for example, all the
movements of a symphony. This plugin aims to solve this problem by not only
fetching the work as in MusicBrainz but also his parentwork which would be,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fetching the work as in MusicBrainz but also his parentwork which would be,
fetching the work itself from MusicBrainz but also its parentwork which would be,

Parentwork Plugin
=================

The `parentwork` plugin fetches the work title, parentwork title and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `parentwork` plugin fetches the work title, parentwork title and
The ``parentwork`` plugin fetches the work title, parentwork title and

If there are several works linked to a recording, they all get a
disambiguation (empty as default) and if all disambiguations are empty, the
disambiguation field is left empty, else the disambiguation field can look
like `,disambig,,` (if there are four works and only the second has a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
like `,disambig,,` (if there are four works and only the second has a
like ``,disambig,,`` (if there are four works and only the second has a

item.artist + ' - ' + item.title)
self._log.debug("Work fetched: " + u', '.join(parent_work) +
' - ' + u', '.join(parent_composer))
item['parent_work'] = u''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines like there aren't necessary since u', '.join([]) == u''

try:
item.parent_work
hasparent = True
except AttributeError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is an AttributeError really raised when accessing a flexible field?

Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for continuing to make progress on this effort!

At a very high level, what do you think about splitting up PRs for the new core functionality and for the plugin? I realize that one depends on the other, but this would make for somewhat easier reviewing and could be part of the flattening that @arcresu brought up (and which I agree might be a good idea at this point).



def work_father(work_id, work_date=None):
""" This function finds the id of the father work given its id"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this docstring should fully describe the return type: namely, it's a pair of an ID and a date. It's also probably worth mentioning that this communicates with MusicBrainz.

work_info = musicbrainzngs.get_work_by_id(work_id,
includes=["work-rels",
"artist-rels"])
if 'artist-relation-list' in work_info['work'] and work_date is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment here could be useful to point out that what we're doing is filling in work_date if it's unspecified (how?).

"""This function finds the parentwork id of a work given its id. """
work_date = None
while True:
(new_work_id, work_date) = work_father(work_id, work_date)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No parentheses are necessary on the left-hand side.

(new_work_id, work_date) = work_father(work_id, work_date)
if not new_work_id:
return work_id, work_date
break
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This break will never be executed.

and work_father.get('direction') == 'backward':
father_id = work_father['work']['id']
return father_id, work_date
return None, work_date
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean to return None as the first part of the tuple here?

self._command.parser.add_option(
u'-f', u'--force', dest='force',
action='store_true', default=None,
help=u'Re-fetches all parent works')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

composer_ids):
"""Given the parentwork info dict, this function updates
parent_composer, parent_composer_sort, parent_work,
parent_work_disambig, work_ids and composer_ids"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer for this function to return information rather than modifying its arguments. The caller can then update all the arrays to collect the data across multiple works.

self._log.info(item.artist + ' - ' + item.title)
self._log.info(
"no composer, add one at https://musicbrainz.org/work/" +
work_info['work']['id'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this log message—if anything, this can go to the debug log.

item['parent_composer'] = u', '.join(parent_composer)
item['parent_composer_sort'] = u''
item['parent_composer_sort'] = u', '.join(parent_composer_sort)
if not (work_date is None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not (work_date is None):
if work_date:

' - ' + u', '.join(parent_composer))
item['parent_work'] = u''
item['parent_work'] = u', '.join(parent_work)
if len(parent_work_disambig) > 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if len(parent_work_disambig) > 0:
if parent_work_disambig:

@dosoe
Copy link
Contributor Author

dosoe commented May 13, 2019

Hi! Thanks for the feedback! I'm not familiar with git or github, so I tried rebasing, but without success I think. Could an easy solution be for me to restart from scratch and decompose it accordingly into different PRs? Splitting between changes to the core and the plugin might be tricky considering that the plugin relies on the changes to the core.

@sampsyo
Copy link
Member

sampsyo commented May 13, 2019

New PRs would work just fine! You could even start with the core fields PR and base the plugin PR on that branch to encode the fact that the latter depends on the former.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants