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

Format length as M:SS by default #1749

Merged
merged 10 commits into from
Dec 13, 2015
Merged

Conversation

diego-plan9
Copy link
Member

As a followup to #1689 and #1737, here is a work-in-progress for trying to make the track lengths be displayed as M:SS instead of the raw number of seconds (and miliseconds).

I'm assuming the intent is that the change is solely a visual one - database should still store the value as a float. To accomplish this, I have followed your suggestion and set Item.length as a custom DurationType(types.Float) with format() and parse() methods that handle the conversion between H:MM and float formats (which has been added to ui to avoid some duplication). Additionally, I have added a DurationQuery(NumericQuery) in order to be able to perform queries using both formats, ie:

$ beet ls length:1:00..2:00
$ beet ls length:60..120

I'd welcome some pointers about potential implications that I might have missed (as I'm still not sure if this change might break some functionality that depends on the length formatting), and ideas about integration tests or any other test to ensure everything works as intended. It's been a busy week on my end (and next one will probably be - sorry about that), but I plan to add at least white-box tests (basically, for library.DurationType, though I'm tempted to also add them for DateType, PathType and MusicalKey, as they are missing) in the next few days.

* Modify library.Item in order to have length formatted as H:MM instead of the
raw number of seconds by using a types.Float subclass (DurationType).
* Add library.DurationType, with custom format() and parse() methods that
handle the conversion.
* Add dbcore.query.DurationQuery as a NumericQuery subclass that _convert()s
the ranges specified by the user to floats, delegating the rest of the
functionality in the parent NumericQuery class.
* Add ui.raw_seconds_short() as the reverse of human_seconds_short(). This
function uses a regular expression in order to allow any number of minutes, and
always required SS to have two digits.
* Add "format_raw_length" global configuration option to allow the user to
toggle between human-readable (default) or raw formatting of track durations.
Raises ValueError if the conversion cannot take place due to `string` not
being in the right format.
"""
match = re.match('^(\d+):([0-5]\d)$', string)
Copy link
Member Author

Choose a reason for hiding this comment

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

A note about using a regexp: I have decided to go through this route to make it consistent with human_seconds_short (ie. format should be (int)M:(int)SS, where SS must be < 60). Using the datetime facilities would restrict M to be < 60.

It might be desirable to make it a bit more flexible (allow HH:MM:SS, or M:SS.zzzzz, etc), and it should not be too hard, but I've opted not to include those for keeping it as an "inverse" of sorts of raw_seconds_short.

Copy link
Member

Choose a reason for hiding this comment

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

Perfect. This seems good for now—and hour-long tracks are certainly an edge case.

@diego-plan9
Copy link
Member Author

Also, this change might reveal a small output discrepancy on the info plugin output with no formatting flag: when using a library query values are shown formatted (length as M:SS, samplerate right as khz, etc); but when using a filename length is still displayed as a raw float string (same for samplerate, etc).

This seems to be due to printing the values from the dict produced by the emitter (which in the case of the filename, is populated from the MediaFile fields).

return None
try:
# TODO: tidy up circular import
from beets.ui import raw_seconds_short
Copy link
Member

Choose a reason for hiding this comment

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

Good point on the circular import—and we mostly try to make dbcore a separate component. Maybe the function should live in this module?

@sampsyo
Copy link
Member

sampsyo commented Dec 6, 2015

Fantastic! You beat me to it. 😃 This looks wonderful.

For this feature, white-box unit tests seem like the right approach to me. You've even updated one case that looks more like an integration test, so I think that should be fine.

And take your time! There's clearly no rush, so no need to apologize for real-life responsibilities.

@diego-plan9
Copy link
Member Author

  • Added some tests for the library-specific field types on library
  • Added changelog entry
  • Moved raw_seconds_short to util

As for the circular import issue mentioned on #1749 (comment), I have moved raw_seconds_short() to beets.util instead of dbcore - it felt a bit out of place to place it directly on dbcore, and seems like other functions on the module are using beets.util anyway. Please let me know if another approach is preferred to meet the architectural goals, and also if perhaps the "inverse" functions (ui.human_seconds() and ui.human_seconds_short() should be moved there as well (there are roughly about ~8 calls to those on the codebase anyway).

The tests are not too extensive but should cover the basic format() and parse() functionality of the types - please let me know if it would be desirable to make them more detailed. Sorry about the commit-noise on one of the tests, it was caused by me not being aware that the DateType output was local time specific.

@sampsyo
Copy link
Member

sampsyo commented Dec 13, 2015

This looks perfect, and the tests will be a great addition by themselves. Sorry for the delay, but I'm merging this now!

@sampsyo sampsyo merged commit 3e2d247 into beetbox:master Dec 13, 2015
sampsyo added a commit that referenced this pull request Dec 13, 2015
Format length as M:SS by default
sampsyo added a commit that referenced this pull request Dec 13, 2015
shamangeorge added a commit to shamangeorge/beets that referenced this pull request Dec 16, 2015
* master: (94 commits)
  Clean up changelog for edit plugin
  scrub: Demote a log message to debug
  scrub: Restore tags & art in auto mode (beetbox#1657)
  scrub: Run on import in auto mode (beetbox#1657)
  Fix beetbox#1673: Escape regex terms in lyrics
  snake_case variable names
  Doc refinements for beetbox#1749
  Remove tests for Google fetchart backend (beetbox#1760)
  fetchart: Remove Google backend (fix beetbox#1760)
  fetchart: Better logging for iTunes (beetbox#1760)
  fetchart: Fix beetbox#1610: itunes install docs
  Fix test that depended on local time, 2
  Fix test that depended on local time
  Fix unused import leftover on test_library
  Add documentation for M:SS length
  Move raw_seconds_short to beets.util
  Add tests for library-specific field types
  Fix test that was expecting raw length format
  Fix pyflakes issues, variable name
  Add config option for human vs raw track duration
  ...
@diego-plan9 diego-plan9 deleted the humanlength branch October 17, 2016 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants