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

lyrics: Crash when BeautifulSoup is not installed #4027

Closed
j-peeters opened this issue Aug 25, 2021 · 5 comments · Fixed by #4076
Closed

lyrics: Crash when BeautifulSoup is not installed #4027

j-peeters opened this issue Aug 25, 2021 · 5 comments · Fixed by #4076
Labels
bug bugs that are confirmed and actionable

Comments

@j-peeters
Copy link

Problem

The Lyrics plugin throws an error/crashes when ran without BeautifulSoup installed.

Terminal output

I currently can't run a verbose command because Beets is dragging itself through finding lyrics for many many albums.

The following error is displayed in Terminal when running:

$ beets lyrics artist song
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/util/confit.py:21: UserWarning: beets.util.confit is deprecated; use confuse instead
  warnings.warn("beets.util.confit is deprecated; use confuse instead")
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/bin/beet", line 11, in <module>
    load_entry_point('beets==1.5.0', 'console_scripts', 'beet')()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/ui/__init__.py", line 1291, in main
    _raw_main(args)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/ui/__init__.py", line 1274, in _raw_main
    subcommands, plugins, lib = _setup(options, lib)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/ui/__init__.py", line 1153, in _setup
    plugins = _load_plugins(options, config)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/ui/__init__.py", line 1139, in _load_plugins
    plugins.send("pluginload")
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/plugins.py", line 497, in send
    for handler in event_handlers()[event]:
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/plugins.py", line 480, in event_handlers
    for plugin in find_plugins():
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/plugins.py", line 315, in find_plugins
    _instances[cls] = cls()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beetsplug/lyrics.py", line 736, in __init__
    sources = self.sanitize_bs_sources(sources)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beetsplug/lyrics.py", line 763, in sanitize_bs_sources
    if source.REQUIRES_BS:
AttributeError: 'str' object has no attribute 'REQUIRES_BS'

After installing BeautifulSoup the output is

/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/beets/util/confit.py:21: UserWarning: beets.util.confit is deprecated; use confuse instead
  warnings.warn("beets.util.confit is deprecated; use confuse instead")

Andrew writes:

We're supposed to silently fix up the configuration when BeautifulSoup is not installed; not crash with a traceback. Glancing at the code, I do see the mistake.

Setup

  • OS: macOS 10.13.6
  • Python version: 3.7
  • beets version: 1.5
  • Turning off plugins made problem go away (yes/no):

My configuration (output of beet config) is:

library: ~/Music/Beets/musiclibrary.db
directory: /Volumes/Tunez

import:
    write: yes
    copy: yes
    move: no
    link: no
    hardlink: no
    delete: no
    resume: ask
    incremental: no
    incremental_skip_later: no
    from_scratch: no
    quiet_fallback: skip
    none_rec_action: ask
    timid: no
    log:
    autotag: yes
    quiet: no
    singletons: no
    default_action: apply
    languages: []
    detail: no
    flat: no
    group_albums: no
    pretend: false
    search_ids: []
    duplicate_action: remove
    bell: no
    set_fields: {}

clutter: ["Thumbs.DB", ".DS_Store"]
ignore: [".*", "*~", "System Volume Information", "lost+found"]
ignore_hidden: yes

replace:
    '[\\/]': _
    '^\.': _
    '[\x00-\x1f]': _
    '[<>:"\?\*\|]': ''
    '\.$': _
    '\s+$': ''
    '^\s+': ''
    '^-': _
path_sep_replace: _
asciify_paths: false
art_filename: cover
max_filename_length: 0

aunique:
    keys: albumartist album
    disambiguators: albumtype year samplerate label catalognum albumdisambig releasegroupdisambig
    bracket: '()'

plugins: 
    - inline
    - the
    - lastgenre
    - discogs
    - chroma
    - acousticbrainz
    - fromfilename
    - fetchart
    - embedart
    - ftintitle
    - edit
    - info
    - missing
    - types
    - convert
    - plexupdate
    - web
    - unimported
    - keyfinder
    - fuzzy
    - spotify
    - describe
    - bpmanalyser
    - lyrics
#    - smartplaylist
#    - goingrunning
pluginpath: 
    - /Users/xxxxxxxx/Documents/BeetsPluginDescribe/beetsplug
threaded: yes
timeout: 5.0
per_disc_numbering: no
verbose: 0
terminal_encoding:
original_date: no
artist_credit: no
id3v23: no
va_name: "Various Artists"

zero:
    fields: comments
    update_database: true

# Inline plugin template
item_fields:
  multidisc: 1 if disctotal > 1 else 0
  my_samplerate: round(samplerate / 1000)
  is_flac: 1 if format == "FLAC" else 0
album_fields:  
  format: |
       formatList = []
       for item in items:
           formatList.append(item.format)
       return formatList
  av_bitrate: |
       total = 0
       for item in items:
           total += item.bitrate
       return round(total / len(items) / 1000)
  album_bitdepth:  |
       total = 0
       for item in items:
           total += item.bitdepth
       return round(total / len(items))
  album_samplerate:  |
       total = 0
       for item in items:
           total += item.samplerate
       return round(total / len(items) / 1000)
  is_1644: |
       bd = 0
       sr = 0
       br = 0
       for item in items:
           bd += item.bitdepth
           sr += item.samplerate
           br += item.bitrate
       bd = round(bd / len(items))
       sr = round(sr / len(items) / 1000)
       br = round(br / len(items) / 1000)
       return 1 if bd == 16 and sr == 44 and br > 320 else 0

ui:
    terminal_width: 80
    length_diff_thresh: 10.0
    color: yes
    colors:
        text_success: green
        text_warning: yellow
        text_error: red
        text_highlight: red
        text_highlight_minor: lightgray
        action_default: turquoise
        action: blue

format_item: $artist - $album - $title
format_album: $albumartist - $album
time_format: '%Y-%m-%d %H:%M:%S'
format_raw_length: no

sort_album: albumartist+ album+
sort_item: artist+ album+ disc+ track+
sort_case_insensitive: yes

paths:
#  default: 'Albums/%the{$albumartist}/$album (%if{$original_year,$original_year}) %aunique{albumartist album year, albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_1644,,%if{$is_flac,($format $bitdepth-$album_samplerate),($format $av_bitrate)}}/%if{$multidisc,$disc-}$track - $title'
  default: 'Albums/%the{$albumartist}/%if{$original_year,$original_year} - $album %aunique{albumartist album year, albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_1644,,%if{$is_flac,($format $album_bitdepth-$album_samplerate),($format $av_bitrate)}}/%if{$multidisc,$disc-}$track - $title'
  dancetrack:1: 'Singles Dance/$artist - $title (%if{$original_year,$original_year}) %aunique{albumartist album year, albumtype label catalognum albumdisambig}%if{$albumdisambig,($albumdisambig$ $year)}($bpm bpm)'
  artistsingles:1: 'Albums/%the{$albumartist}/$album/$title'
  custcomp:1: 'Compilations/$album/$track - $artist - $title'
  custcompmin:1: 'Compilations/$album/$artist - $title'
  singleton: 'Singles/$artist - $title %aunique{albumartist album year, albumtype label catalognum albumdisambig}%if{$albumdisambig,($albumdisambig$ $year)}'
  comp: 'Albums/%the{$albumartist}/$album (%if{$original_year,$original_year}) %aunique{albumartist album year, albumtype label catalognum albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_1644,,%if{$is_flac,($format $bitdepth-$album_samplerate),($format $av_bitrate)}}/%if{$multidisc,$disc-}$track - $artist - $title'


statefile: state.pickle

musicbrainz:
    host: musicbrainz.org
    ratelimit: 1
    ratelimit_interval: 1.0
    searchlimit: 5

match:
    strong_rec_thresh: 0.04
    medium_rec_thresh: 0.25
    rec_gap_thresh: 0.25
    max_rec:
        missing_tracks: medium
        unmatched_tracks: medium
    distance_weights:
        source: 2.0
        artist: 3.0
        album: 3.0
        media: 1.0
        mediums: 1.0
        year: 1.0
        country: 0.5
        label: 0.5
        catalognum: 0.5
        albumdisambig: 0.5
        album_id: 5.0
        tracks: 2.0
        missing_tracks: 0.9
        unmatched_tracks: 0.6
        track_title: 3.0
        track_artist: 2.0
        track_index: 1.0
        track_length: 2.0
        track_id: 5.0
    preferred:
        countries: []
        media: ['Digital Media|File' , 'CD']
        original_year: no
    ignored: []
    required: []
    ignored_media: []
    ignore_data_tracks: yes
    ignore_video_tracks: yes
    track_length_grace: 10
    track_length_max: 30
    
chroma:
    auto: no
    
fetchart:
    auto: yes
    cautious: no
    cover_names: cover front art album folder
    minwidth: 290
    maxwidth: 1050
    sources: itunes amazon albumart lastfm fanart filesystem coverart 
    fanarttv_key: xxxxxxxxxxxxx
    lastfm_key: xxxxxxxxxxxx
    
acoustid: 
    apikey: xxxxxxxxx
   
embedart:
    auto: yes
    ifempty: no   
    
lastgenre:
    auto: yes
    canonical: no
    count: 1
    force: yes
    source: album
    whitelist: yes
    min_weight: 10
    fallback:
    separator: ', '
    prefer_specific: no
    
types:
    av_bitrate: int
    my_samplerate: int
    bitdepth: int
    album_bitdepth: int
    album_samplerate: int
    rating: int
    
convert:
    dest: ~/Music/BeetExports
    command: ffmpeg -i $source -y -vn -aq 0 $dest    
    extension: mp3
    format: mp3
    never_convert_lossy_files: yes

plex:
    host: localhost
    port: 32400
    token: xxxxxxxxxxxxxx
    
lastfm:
    user: xxxxxxxxxx
    
smartplaylist:
    playlist_dir: /Users/Shared/Music/Playlists
    auto: no
    playlists:
        - name: 'favorites.m3u' 
          query: rating:4..5
        - name: 'danceable.m3u'
          query: 
            - danceable:0.8..
        - name: 'acoustic.m3u'
          query: 
            - mood_acoustic:0.8..
        - name: 'aggresive.m3u'
          query: 
            - mood_aggresive:0.8..
        - name: 'electronic.m3u'
          query: 
            - mood_electronic:0.8..
        - name: 'danceable.m3u'
          query: 
            - danceable:0.8..
        - name: 'happy.m3u'
          query: 
            - mood_happy:0.8..           
        - name: 'party.m3u'
          query: 
            - mood_party:0.8.. 
        - name: 'relaxed.m3u'
          query: 
            - mood_relaxed:0.8..                   
        - name: 'sad.m3u'
          query: 
            - mood_sad:0.8..

spotify:
    mode: list
    show_failures: on
    tiebreak: first
    
bpmanalyser:
    auto: no
    dry-run: no
    write: yes
    force: no
    quiet: no
    
goingrunning:
  targets:
    subsonic_m3u:
      device_root: /Users/Shared/Music/Playlists
      device_path: 
      clean_target: yes
      generate_playlist: yes
      copy_files: no
  trainings:
    10K:
      use_flavours: [intensity_low, intensity_high, running]
      duration: 180
      target: subsonic_m3u
  flavours:
    intensity_low:
      bpm: 87..88
    intensity_high:
      bpm: 175..177
    running:
      genre: [electronic, hip hop, funk, trip hop, house]

web:
    host: 0.0.0.0
    cors: 'http://localhost:3000'
    
lyrics:
    auto: yes
    google_API_key: xxxxxxxxxxxxxxxxx
    google_engine_ID: 009217259823014548361:lndtuqkycfu
    
unimported:
    ignore_extensions: mid wav
@sampsyo sampsyo added the bug bugs that are confirmed and actionable label Aug 25, 2021
@sampsyo sampsyo changed the title Lyrics plugin crashes after update to Beets 1.5 lyrics: Crash when BeautifulSoup is not installed Aug 25, 2021
@sampsyo
Copy link
Member

sampsyo commented Aug 25, 2021

Thanks! This looks like a recently-introduced bug. The root cause is a function that expects a Source object but is actually receiving a string.

@ctrueden
Copy link
Contributor

The commit that introduced this bug is 316b79f by @wisp3rwind.

@j-peeters
Copy link
Author

Thanks for fixing this! I'm a total newbie with branches, masters, fixes etc.
If I want to use this fix, how do I update Beets to include this new fix? I'm currently on the 1.5 version.

@sampsyo
Copy link
Member

sampsyo commented Oct 1, 2021

The FAQ has instructions:
https://beets.readthedocs.io/en/stable/faq.html#run-the-latest-source-version-of-beets

@ctrueden
Copy link
Contributor

ctrueden commented Oct 1, 2021

@sampsyo Side question about that: I notice the docs don't mention the pattern:

git clone git://github.com/beetbox/beets
cd beets
pip install -e .

to install beets from source in editable mode. Should we add it? The advantage is that you can then hack on your beets working copy, and the changes are immediately reflected in your environment without needing to run python setup.py install every time. This is how I've been developing my beets plugins, and I find it very convenient. Or is there some downside to pip install -e that I don't know (I'm not super expert at python)?

Edit: Reading more carefully, I see that pip install -e is the third option listed... but using the "automatic source checkout" approach. So I guess the distinction here is merely whether you clone it manually yourself, and therefore get to decide where the sources go? *shrug*

Edit 2: I filed #4084 suggesting an addition to the FAQ about pip install -e .. Please feel free to close if it's not to your liking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug bugs that are confirmed and actionable
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants