Repository: beetbox/beets

Issue:
convert: Close stdin for ffmpeg subprocesses
### Problem

Sometimes when running multiple consecutive beets commands, stdio gets confused and the enter key stops working. Seems to happen particularly often with the convert plugin, but I have also observed it when importing.

Steps to reproduce:
1. convert any album with `beet convert -a foo`, just hit enter in the confirmation prompt
2. try to convert another album with `beet convert -a bar`, hit enter in the confirmation prompt
3. instead a newline, a literal "^M" appears when pressing either the enter key or ^M
4. kill beets with ^C and run `reset`
5. try 2. again, now it works as expected

### Setup

* OS: NixOS 17.09pre102667.2839b10 (Linux 4.9.13)
* Python version: 2.7.13
* beets version: 1.4.3
* Turning off plugins made problem go away (yes/no): -

My configuration (output of `beet config`) is:
```yaml
mpd:
    password: REDACTED
    rating: yes
    rating_mix: 0.75
    host: localhost
    music_directory: /media/music
    port: 6600
fetchart:
    sources: [filesystem]
    store_source: yes
    auto: yes
    minwidth: 0
    google_engine: 001442825323518660753:hrh5ch1gjzm
    enforce_ratio: no
    cautious: no
    maxwidth: 0
    google_key: REDACTED
    fanarttv_key: REDACTED
    cover_names:
    - cover
    - front
    - art
    - album
    - folder
play:
    command: mpc insert
    relative_to: /media/music
    warning_treshold: 30
    raw: yes
    use_folders: no
    warning_threshold: 100

replace:
    '[\\/]': _
    ^\.: _
    '[\x00-\x1f]': _
    '[<>:"\?\*\|]': _
    \.$: _
    \s+$: ''
    ^\s+: ''
replaygain:
    backend: bs1770gain
    method: ebu
    targetlevel: 89
    auto: yes
    overwrite: no
    chunk_at: 5000

plugins: acousticbrainz badfiles convert edit embedart fetchart ftintitle fuzzy info keyfinder mbsync missing mpdstats mpdupdate play replaygain random the web
fuzzy:
    prefix: "\xA7"
    threshold: 0.7
ignore_hidden: yes

paths:
    default: '%the{$albumartist}/%the{$album}/$track-$title'
    singleton: '%the{$artist}-%the{$title}'
    comp: '%the{$album}/$track-$title'
    albumtype:soundtrack: Soundtracks/%the{$album}/$track-$title
    albumtype:single: '%the{$albumartist}/%the{$album}/$track-$title'
convert:
    embed: yes
    album_art_maxwidth: 900
    format: aac
    dest: /nas/media/library_aac
    copy_album_art: yes
    formats:
        aac:
            command: ffmpeg -i $source -y -vn -acodec aac -aq 1 -ar 48k $dest
            extension: m4a
        opus:
            command: ffmpeg -i $source -y -vn -acodec libopus -ab 128k $dest
        version:
            command: ffmpeg
        alac:
            command: ffmpeg -i $source -y -vn -acodec alac $dest
            extension: m4a
        mp3: ffmpeg -i $source -y -vn -aq 2 $dest
        flac: ffmpeg -i $source -y -vn -acodec flac $dest
        ogg: ffmpeg -i $source -y -vn -acodec libvorbis -aq 3 $dest
        wma: ffmpeg -i $source -y -vn -acodec wmav2 -vn $dest
    never_convert_lossy_files: no
    auto: no
    threads: 4
    tmpdir:
    max_bitrate: 500

    paths: {}
    pretend: no
    quiet: no
threaded: yes
art_filename: folder
ignore: .AppleDouble ._* *~ .DS_Store

ui:
    color: yes
directory: /media/music

import:
    incremental: yes
the:
    a: yes
    patterns: []
    the: yes
    strip: no
    format: '{0}, {1}'
web:
    host: 127.0.0.1
    port: 8337
    cors: ''
keyfinder:
    bin: keyfinder-cli
    auto: yes
    overwrite: no
missing:
    count: no
    total: no
edit:
    itemfields: track title artist album
    albumfields: album albumartist
    ignore_fields: id path
ftintitle:
    auto: yes
    drop: no
    format: feat. {0}
acousticbrainz:
    auto: yes
    force: no
embedart:
    compare_threshold: 0
    auto: yes
    ifempty: no
    remove_art_file: no
    maxwidth: 0
```



Discussion:
Thanks! This sounds like a similar problem to https://github.com/beetbox/audioread/issues/32 in the Audioread project, which also forks ffmpeg subprocesses. It was fixed in https://github.com/beetbox/audioread/commit/ea48fd7dc3ffd2b3223c792227c7850e6e9e7185, where the solution was to hook up the subprocess's stdin to /dev/null. I believe we need to do the same thing [here](https://github.com/beetbox/beets/blob/91b65ca5ab8ecdc691454c50d2e5ca74857fc79d/beets/util/__init__.py#L800-L806), where we invoke the command for the convert plugin.
I noticed it as well, but never went into it. Glad that this is getting attention!

Resolving patch:
diff --git a/beets/util/__init__.py b/beets/util/__init__.py
--- a/beets/util/__init__.py
+++ b/beets/util/__init__.py
@@ -797,10 +797,16 @@ def command_output(cmd, shell=False):
     """
     cmd = convert_command_args(cmd)
 
+    try:  # python >= 3.3
+        devnull = subprocess.DEVNULL
+    except AttributeError:
+        devnull = open(os.devnull, 'r+b')
+
     proc = subprocess.Popen(
         cmd,
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
+        stdin=devnull,
         close_fds=platform.system() != 'Windows',
         shell=shell
     )


Test patch: