Code Monkey home page Code Monkey logo

whipper's Introduction

Whipper

license Build Status GitHub (pre-)release IRC GitHub Stars GitHub Issues GitHub contributors

Whipper is a Python 3 (3.6+) CD-DA ripper based on the morituri project (CDDA ripper for *nix systems aiming for accuracy over speed). It started just as a fork of morituri - which development seems to have halted - merging old ignored pull requests, improving it with bugfixes and new features. Nowadays whipper's codebase diverges significantly from morituri's one.

Whipper is currently developed and tested only on Linux distributions but may work fine on other *nix OSes too.

In order to track whipper's latest changes it's advised to check its commit history (README and CHANGELOG files may not be comprehensive).

Table of content

Rationale

For a detailed description, see morituri's wiki page: The Art of the Rip.

Features

  • Detects correct read offset (in samples)
  • Detects whether ripped media is a CD-R
  • Has ability to defeat cache of drives
  • Performs Test & Copy rips
  • Verifies rip accuracy using the AccurateRip database
  • Uses MusicBrainz for metadata lookup
  • Supports reading the pre-emphasis flag embedded into some CDs (and correctly tags the resulting rip)
    • Currently whipper only reports the pre-emphasis flag value stored in the TOC
  • Detects and rips non digitally silent Hidden Track One Audio (HTOA)
  • Provides batch ripping capabilities
  • Provides templates for file and directory naming
  • Supports lossless encoding of ripped audio tracks (FLAC)
  • Allows extensibility through external logger plugins

Changelog

See CHANGELOG.md.

For detailed information, please check the commit history.

Installation

Whipper still isn't available as an official package in every Linux distributions so, in order to use it, it may be necessary to build it from its source code.

Docker

You can easily install whipper without needing to care about the required dependencies by making use of the automatically built images hosted on Docker Hub:

docker pull whipperteam/whipper

Please note that, right now, Docker Hub only builds whipper images for the amd64 architecture: if you intend to use them on a different one, you'll need to build the images locally (as explained below).

Building the Docker image locally is required in order to make it work on Arch Linux (and its derivatives) because of a group permission issue (for more details see issue #499).

To build the Docker image locally just issue the following command (it relies on the Dockerfile included in whipper's repository):

optical_gid=$(getent group optical | cut -d: -f3) uid=$(id -u) docker build --build-arg optical_gid --build-arg uid -t whipperteam/whipper .

It's recommended to create an alias for a convenient usage:

alias whipper="docker run -ti --rm --device=/dev/cdrom \
    --mount type=bind,source=${HOME}/.config/whipper,target=/home/worker/.config/whipper \
    --mount type=bind,source=${PWD}/output,target=/output \
    whipperteam/whipper"

You should put this e.g. into your .bash_aliases. Also keep in mind to replace the path definitions to something that fits to your needs (e.g. replace … -v ${PWD}/output:/output … with … -v ${HOME}/ripped:/output \ …).

Essentially, what this does is to map the /home/worker/.config/whipper and ${PWD}/output (or whatever other directory you specified) on your host system to locations inside the Docker container where the files can be written and read. These directories need to exist on your system before you can run the container:

mkdir -p "${HOME}/.config/whipper" "${PWD}/output"

Please note that the example alias written above only provides access to a single disc drive: if you've got many you will need to customise it in order to use all of them in whipper's Docker container.

Finally, you can test the correct installation as such:

whipper -v
whipper drive list

Package

This is a noncomprehensive summary which shows whipper's packaging status (unofficial repositories are probably not included):

Packaging status

NOTE: if installing whipper from an unofficial repository please keep in mind it is your responsibility to verify that the provided content is safe to use.

Building

If you are building from a source tarball or checkout, you can choose to use whipper installed or uninstalled but first install all the required dependencies.

Required dependencies

Whipper relies on the following packages in order to run correctly and provide all the supported features:

  • cd-paranoia, for the actual ripping
    • To avoid bugs it's advised to use cd-paranoia versions ≥ 10.2+0.94+2
    • The package named libcdio-utils, available on older Debian and Ubuntu versions, is affected by a bug: it doesn't include the cd-paranoia binary (needed by whipper). Starting with Debian bullseye (11) and Ubuntu focal (20.04), a separatecd-paranoia package is available which provides the aforementioned binary. For more details on this issue, please check the relevant bug reports: #888053 (Debian), #889803 (Debian) and #1750264 (Ubuntu).
  • cdrdao, for session, TOC, pre-gap, and ISRC extraction
  • musicbrainzngs, for metadata lookup
  • mutagen, for tagging support
  • setuptools, for installation, plugins support
  • pycdio, for drive identification (required for drive offset and caching behavior to be stored in the configuration file).
    • To avoid bugs it's advised to use the most recent pycdio version with the corresponding libcdio release or, if stuck on old pycdio versions, 0.20/0.21 with libcdio0.900.94. All other combinations won't probably work.
  • discid, for calculating Musicbrainz disc id.
  • ruamel.yaml, for generating well formed YAML report logfiles
  • libsndfile, for reading wav files
  • flac, for reading flac files
  • sox, for track peak detection
  • git or mercurial
    • Required either when running whipper without installing it or when building it from its source code (code cloned from a git/mercurial repository).

Some dependencies aren't available in the PyPI. They can be probably installed using your distribution's package manager:

PyPI installable dependencies are listed in the requirements.txt file and can be installed issuing the following command:

pip3 install -r requirements.txt

Optional dependencies

  • Pillow, for completely supporting the cover art feature (embed and complete option values won't work otherwise).
  • docutils, to build the man pages.

These dependencies are not listed in the requirements.txt. To install them, just issue the following command:

pip3 install Pillow docutils

Fetching the source code

Change to a directory where you want to put whipper source code (for example, $HOME/dev/ext or $HOME/prefix/src)

git clone https://github.com/whipper-team/whipper.git
cd whipper

Finalizing the build

Install whipper: python3 setup.py install

Note that, depending on the chosen installation path, this command may require elevated rights.

To build the man pages, follow the instructions in the relevant README which is located in the man subfolder.

Usage

Whipper currently only has a command-line interface called whipper which is self-documenting: whipper -h gives you the basic instructions.

Whipper implements a tree of commands: for example, the top-level whipper command has a number of sub-commands.

Positioning of arguments is important:

whipper cd -d (device) rip

is correct, while

whipper cd rip -d (device)

is not, because the -d argument applies to the cd command.

A more complete set of usage instructions can be found in the whipper man pages.

Getting started

The simplest way to get started making accurate rips is:

  1. Pick a relatively popular CD that has a good chance of being in the AccurateRip database

  2. Analyze the drive's caching behavior

    whipper drive analyze

  3. Find the drive's offset.

    Consult the AccurateRip's CD Drive Offset database for your drive. Drive information can be retrieved with whipper drive list.

    whipper offset find -o insert-numeric-value-here

    If you omit the -o argument, whipper will try a long, popularity-sorted list of drive offsets.

    Please note that whipper's offset find feature is quite primitive so it may not always achieve its task: in this case using the value listed in AccurateRip's CD Drive Offset database should be enough.

    If you can not confirm your drive offset value but wish to set a default regardless, set read_offset = insert-numeric-value-here in whipper.conf.

    Offsets confirmed with whipper offset find are automatically written to the configuration file.

    If specifying the offset manually, please note that: if positive it must be written as a number without sign (ex: +102 -> 102), if negative it must include the sign too (ex: -102 -> -102).

  4. Rip the disc by running

    whipper cd rip

Configuration file documentation

The configuration file is stored in $XDG_CONFIG_HOME/whipper/whipper.conf, or $HOME/.config/whipper/whipper.conf if $XDG_CONFIG_HOME is undefined.

See XDG Base Directory Specification and ConfigParser with inline_comment_prefixes=(';').

The configuration file consists of newline-delineated [sections] containing key = value pairs. The sections [main] and [musicbrainz] are special config sections for options not accessible from the command line interface. Sections beginning with drive are written by whipper; certain values should not be edited. Inline comments can be added using ;.

Example configuration demonstrating all [main] and [musicbrainz] options:

[main]
path_filter_dot = True			; replace leading dot with _
path_filter_posix = True		; replace illegal chars in *nix OSes with _
path_filter_vfat = False		; replace illegal chars in VFAT filesystems with _
path_filter_whitespace = False		; replace all whitespace chars with _
path_filter_printable = False		; replace all non printable ASCII chars with _

[musicbrainz]
server = https://musicbrainz.org	; use MusicBrainz server at host[:port]
# use http as scheme if connecting to a plain http server. Example below:
# server = http://example.com:8080

[drive:HL-20]
defeats_cache = True			; whether the drive is capable of defeating the audio cache
read_offset = 6				; drive read offset in positive/negative frames (no leading +)
# do not edit the values 'vendor', 'model', and 'release'; they are used by whipper to match the drive

# command line defaults for `whipper cd rip`
[whipper.cd.rip]
unknown = True
output_directory = ~/My Music
# Note: the format char '%' must be represented '%%'.
# Do not add inline comments with an unescaped '%' character (else an 'InterpolationSyntaxError' will occur).
track_template = new/%%A/%%y - %%d/%%t - %%n
disc_template =  new/%%A/%%y - %%d/%%A - %%d
# ...

Running uninstalled

To make it easier for developers, you can run whipper straight from the source checkout:

python3 -m whipper -h

Logger plugins

Whipper allows using external logger plugins to customize the template of .log files.

The available plugins can be listed with whipper cd rip -h. Specify a logger to rip with by passing -L loggername:

whipper cd rip -L eac

Whipper searches for logger plugins in the following paths:

  • $XDG_DATA_HOME/whipper/plugins

  • Paths returned by the following Python instruction:

    [x + '/whipper/plugins' for x in site.getsitepackages()]

  • If whipper is run in a virtualenv, it will use these alternative instructions (from distutils.sysconfig):

    • get_python_lib(plat_specific=False, standard_lib=False, prefix='/usr/local') + '/whipper/plugins'
    • get_python_lib(plat_specific=False, standard_lib=False) + '/whipper/plugins'

On a default Debian/Ubuntu installation, the following paths are searched by whipper:

  • $HOME/.local/share/whipper/plugins
  • /usr/local/lib/python3.X/dist-packages/whipper/plugins
  • /usr/lib/python3.X/dist-packages/whipper/plugins

Where X stands for the minor version of the Python 3 release available on the system.

Please note that locally installed logger plugins won't be recognized when whipper has been installed through the official Docker image.

Official logger plugins

I suggest using whipper's default logger unless you've got particular requirements.

License

Licensed under the GNU GPLv3 license.

Copyright (C) 2009 Thomas Vander Stichele
Copyright (C) 2016-2021 The Whipper Team: JoeLametta, Samantha Baldwin,
                        Merlijn Wajer, Frederik “Freso” S. Olesen, et al.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

Contributing

Make sure you have the latest copy from our git repository. Where possible, please include tests for new or changed functionality. You can run tests with python3 -m unittest discover from your source checkout.

Developer Certificate of Origin (DCO)

To make a good faith effort to ensure licensing criteria are met, this project requires the Developer Certificate of Origin (DCO) process to be followed.

The Developer Certificate of Origin (DCO) is a document that certifies you own and/or have the right to contribute the work and license it appropriately. The DCO is used instead of a much more annoying CLA (Contributor License Agreement). With the DCO, you retain copyright of your own work :). The DCO originated in the Linux community, and is used by other projects like Git and Docker.

The DCO agreement is shown below, and it's also available online: HERE.

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

DCO Sign-Off Methods

The DCO requires a sign-off message in the following format appear on each commit in the pull request:

Signed-off-by: Full Name <email>

The DCO text can either be manually added to your commit body, or you can add either -s or --signoff to your usual Git commit commands. If you forget to add the sign-off you can also amend a previous commit with the sign-off by running git commit --amend -s.

Bug reports & feature requests

Please use the issue tracker to report any bugs or to file feature requests.

When filing bug reports, please run the failing command with the environment variable WHIPPER_DEBUG set. For example:

WHIPPER_DEBUG=DEBUG WHIPPER_LOGFILE=whipper.log whipper offset find
gzip whipper.log

Finally, attach the gzipped log file to your bug report.

Without WHIPPER_LOGFILE set, logging messages will go to stderr. WHIPPER_DEBUG accepts a string of the default python logging levels.

If you can, please try to help to solve THIS issue which also has an open bounty on Bountysource.

Credits

Thanks to:

And to all the contributors.

Links

You can find us and talk about the project on:

Other relevant links:

whipper's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

whipper's Issues

UnicodeEncodeError

I got this error after track seven has finished for the cd https://musicbrainz.org/release/8a76dde5-287d-4cb2-88e0-5c7a621c654c:

Traceback (most recent call last):
  File "/usr/local/bin/rip", line 37, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/main.py", line 40, in main
    ret = c.parse(argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/main.py", line 118, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/cd.py", line 174, in do
    self.doCommand()
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/cd.py", line 482, in doCommand
    ripIfNotRipped(i + 1)
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/cd.py", line 376, in ripIfNotRipped
    if os.path.exists(path):
  File "/usr/lib/python2.7/genericpath.py", line 18, in exists
    os.stat(path)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 92: ordinal not in range(128)

[musicbrainz] KeyError: 'disc'

Hi, when trying to rip a disc I'm having the following traceback:

...
CDDB disc id: 610ee607                        
MusicBrainz disc id Prl80A5pLQK5FAWqsdcwYwpX.UM-
MusicBrainz lookup URL https://musicbrainz.org/cdtoc/attach?toc=1+7+286270+150+46504+94265+137781+182147+214584+253420&tracks=7&id=Prl80A5pLQK5FAWqsdcwYwpX.UM-
Disc duration: 01:03:34.933, 7 audio tracks
Traceback (most recent call last):
  File "/usr/bin/rip", line 41, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 45, in main
    ret = c.parse(argv)
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 123, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/usr/lib/python2.7/site-packages/morituri/rip/cd.py", line 101, in do
    prompt=self.options.prompt)
  File "/usr/lib/python2.7/site-packages/morituri/common/program.py", line 344, in getMusicBrainz
    record=self._record)
  File "/usr/lib/python2.7/site-packages/morituri/common/mbngs.py", line 289, in musicbrainz
    len(result['disc']['release-list']),
KeyError: 'disc'

This is on an up-to-date Arch box with whipper-git from AUR.

Thanks!

whatlogger no longer recognized

I just updated whipper a few days ago. I installed whatlogger using the instructions from the readme file. I have whatlogger set as the default logger in the conf file for whipper but when trying to rip a cd it tells me no logger named what found. Could this be because of the backward incompatible changes that were made? Using the whatlogger is essential if whipper is going to be adopted by what.cd as an approved ripper.

Migrate away from the "rip" command

Hi!

I've been thinking for a while now that morituri's rip command is pretty badly named. Normally, when you download a program you kinda expect to be able to call it by it's name and not some other name!

Since you decided to fork morituri, I find it even more confusing, since both of them now use the same utility name...

Why don't you migrate away from it and use whipper as the way to call the program?

Use a single standard for config/cache/state files

Not everything makes use of morituri.common.directory.Directory to decide where to read/write files, which leads to some files ending up in /.morituri/, and others in XDG directories (/.config/morituri, ~/.cache/morituri by default).

Everything should either follow XDG or the old standard.

# Uses of Directory.getConfig
morituri/common/config.py:        return directory.Directory().getConfig()
morituri/test/test_common_directory.py:        path = d.getConfig()

# Uses of Directory.getCache
morituri/common/cache.py:            self._path = d.getCache('table')
morituri/test/test_common_directory.py:        path = d.getCache()

# Uses of old style config directory
morituri/common/accurip.py:_CACHE_DIR = os.path.join(os.path.expanduser('~'), '.morituri', 'cache')
morituri/common/cache.py:        path = os.path.join(os.path.expanduser('~'), '.morituri', 'cache',
morituri/rip/main.py:    homepluginsdir = os.path.join(os.path.expanduser('~'),

It would also make sense to only allow one location for the config file, especially if we are to rename it (i.e. whipper.conf rather morituri.conf). Right now both ~/.config/morituri/morituri.conf and ~/.moriturirc are allowed.

wrong status code when giving up

When I get this error message:

Calculating CRC (6 of 7) ...  99 %                 
Calculating CRC (6 of 7) ... 100 %                 

Calculating CRC (6 of 7) ...   0 %                 
Calculating peak level (7 of 7) ...   0 %          
Calculating peak level (7 of 7) ...   0 %          
ERROR [18950] "rip"                            rip               Okt 29 13:04:04      Giving up on track 15 after 5 times (morituri/rip/cd.py:423)

then whipper returns a zero status code. I would expect something that is non zero for further processing within a script.

whipper fails to build on bash-compgen

make[2]: Entering directory '/home/samantha/prj/whipper-build/etc/bash_completion.d'
PYTHONPATH=../..:$PYTHONPATH ./bash-compgen \
    rip morituri.rip.main.Rip > rip
  File "./bash-compgen", line 178
    exec command
               ^
SyntaxError: Missing parentheses in call to 'exec'`

I have run through the git submodule init, git submodule update ./autogen.sh and ./configure as specified in the README.

offset find fails

[arch@arch Music]$ rip offset find
Checking device /dev/cdrom
eject: CD-ROM tray close command failed: Input/output error
Trying read offset 6 ...                      
** Message: pygobject_register_sinkfunc is deprecated (GstObject)
Offset of device is likely 6, confirming ...  

Read offset of device is: 6.
Adding read offset to configuration file.
Traceback (most recent call last):
  File "/usr/bin/rip", line 36, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 40, in main
    ret = c.parse(argv)
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 116, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/usr/lib/python2.7/site-packages/morituri/rip/offset.py", line 200, in do
    self._foundOffset(device, offset)
  File "/usr/lib/python2.7/site-packages/morituri/rip/offset.py", line 248, in _foundOffset
    offset)
  File "/usr/lib/python2.7/site-packages/morituri/common/config.py", line 89, in setReadOffset
    section = self._findOrCreateDriveSection(vendor, model, release)
  File "/usr/lib/python2.7/site-packages/morituri/common/config.py", line 160, in _findOrCreateDriveSection
    self.write()
  File "/usr/lib/python2.7/site-packages/morituri/common/config.py", line 62, in write
    shutil.move(path, self._path)
  File "/usr/lib/python2.7/shutil.py", line 302, in move
    copy2(src, real_dst)
  File "/usr/lib/python2.7/shutil.py", line 130, in copy2
    copyfile(src, dst)
  File "/usr/lib/python2.7/shutil.py", line 83, in copyfile
    with open(dst, 'wb') as fdst:
IOError: [Errno 2] No such file or directory: u'/home/arch/.config/whipper/whipper.conf'

Include most possible unattended rip workflow script into whipper's repository

Hello team and users,

while ripping my collection I've created a script to rip my CDs with almost no manual attention by me. I thought this might be interesting for other users too. With this script the only thing the left for you to do is replacing the CDs in your drive.

https://github.com/thomas-mc-work/most-possible-unattended-rip

@JoeLametta: maybe you even like to include this into your project or wiki to help other users getting started with this faster.

Use user submitted MusicBrainz Data

If a cd is unknown at MusicBrainz you'd mostly got a problem like this:

[arch@arch Music]$ rip cd rip --offset 6 --track-template="%R/%A/%d/%t. %n" --disc-template="%R/%A/%d/%A - %d"
Checking device /dev/sr0
eject: CD-ROM tray close command failed: Input/output error
CDDB disc id: 4c12f916                        
MusicBrainz disc id kKrMj0RknVuwLKBn1Om8hwcJbu0-
MusicBrainz lookup URL https://musicbrainz.org/cdtoc/attach?toc=1+22+364477+150+15933+33032+46481+64238+81046+97359+114482+131698+147732+163788+181038+196001+211996+229416+247124+264883+282083+299542+317168+332494+349483&tracks=22&id=kKrMj0RknVuwLKBn1Om8hwcJbu0-
Disc duration: 01:20:57.693, 22 audio tracks
Continuing without metadata
Submit this disc to MusicBrainz at the above URL.

FreeDB identifies disc as Scooter / 20 Years Of Hardcore CD 01

However MusicBrainz offers you to enter the data youself without registration. That is not in the official database then, but (it looks to me) still available for everyone:
https://musicbrainz.org/cdstub/kKrMj0RknVuwLKBn1Om8hwcJbu0-

If a user entered dataset could be read as alternative that'd be great. I've use the whipper archlinux package from aur, so I guess my musicbrainz is up to date. Maybe its an upstream issue of that module instead.

Error reading TOC

Thank you for continuous work on Whipper. With one of my CDs I am getting this error:

Using configured read offset 667
Checking device /dev/sr0
rip: error: cannot read CD from drive... 100 %
cdrdao says:
Cannot read disk toc.

Using cdrdao directly with the same CD also gives me an error (see below) but eventually completes successfully. All of these messages are just Greek to me. Is there any way I can rip this CD?

Thanks
ooglyhLL

Cdrdao version 1.2.3 - (C) Andreas Mueller <[email protected]>
/dev/sr0: HL-DT-ST DVDRAM GH22NS50  Rev: TN03
Using driver: Generic SCSI-3/MMC - Version 2.0 (options 0x0000)

Reading toc data...
ERROR: Cannot read disk toc.

Track   Mode    Flags  Start                Length
------------------------------------------------------------
 1      AUDIO   0      00:00:00(     0)     02:16:08( 10208)
 2      AUDIO   0      02:16:08( 10208)     02:24:12( 10812)
 3      AUDIO   0      04:40:20( 21020)     02:32:00( 11400)
 4      AUDIO   0      07:12:20( 32420)     02:16:30( 10230)
 5      AUDIO   0      09:28:50( 42650)     02:13:33( 10008)
 6      AUDIO   0      11:42:08( 52658)     02:44:40( 12340)
 7      AUDIO   0      14:26:48( 64998)     02:20:70( 10570)
 8      AUDIO   0      16:47:43( 75568)     03:02:38( 13688)
 9      AUDIO   0      19:50:06( 89256)     03:34:10( 16060)
10      AUDIO   0      23:24:16(105316)     03:17:60( 14835)
11      AUDIO   0      26:42:01(120151)     03:15:30( 14655)
12      AUDIO   0      29:57:31(134806)     03:12:27( 14427)
13      AUDIO   0      33:09:58(149233)     02:51:18( 12843)
14      AUDIO   0      36:01:01(162076)     02:55:50( 13175)
15      AUDIO   0      38:56:51(175251)     03:04:47( 13847)
16      AUDIO   0      42:01:23(189098)     03:39:32( 16457)
17      AUDIO   0      45:40:55(205555)     04:10:46( 18796)
18      AUDIO   0      49:51:26(224351)     03:53:05( 17480)
19      AUDIO   0      53:44:31(241831)     02:26:02( 10952)
20      AUDIO   0      56:10:33(252783)     02:51:05( 12830)
Leadout AUDIO   0      59:01:38(265613)

PQ sub-channel reading (audio track) is supported, data format is BCD.
Raw P-W sub-channel reading (audio track) is supported.
Analyzing track 01 (AUDIO): start 00:00:00, length 02:16:08...
Found 40 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 02 (AUDIO): start 02:16:08, length 02:24:12...
Found pre-gap: 00:02:55
Found 21 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 03 (AUDIO): start 04:40:20, length 02:32:00...
Found pre-gap: 00:02:57
Found 33 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 04 (AUDIO): start 07:12:20, length 02:16:30...
Found pre-gap: 00:02:55
Found 27 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 05 (AUDIO): start 09:28:50, length 02:13:33...
Found pre-gap: 00:02:56
Found 18 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 06 (AUDIO): start 11:42:08, length 02:44:40...
Found pre-gap: 00:02:55
Found 36 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 07 (AUDIO): start 14:26:48, length 02:20:70...
Found pre-gap: 00:02:55
Found 21 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 08 (AUDIO): start 16:47:43, length 03:02:38...
Found pre-gap: 00:02:58
Found 39 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 09 (AUDIO): start 19:50:06, length 03:34:10...
Found pre-gap: 00:02:56
Found 107 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 10 (AUDIO): start 23:24:16, length 03:17:60...
Found pre-gap: 00:02:56
Found 108 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 11 (AUDIO): start 26:42:01, length 03:15:30...
Found pre-gap: 00:02:56
Found 156 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 12 (AUDIO): start 29:57:31, length 03:12:27...
Found pre-gap: 00:02:56
Found 36 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 13 (AUDIO): start 33:09:58, length 02:51:18...
Found pre-gap: 00:02:55
Found 607 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 14 (AUDIO): start 36:01:01, length 02:55:50...
Found pre-gap: 00:02:56
Found 61 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 15 (AUDIO): start 38:56:51, length 03:04:47...
Found pre-gap: 00:02:56
Found 54 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 16 (AUDIO): start 42:01:23, length 03:39:32...
Found pre-gap: 00:02:55
Found 140 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 17 (AUDIO): start 45:40:55, length 04:10:46...
Found pre-gap: 00:02:55
Found 56 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 18 (AUDIO): start 49:51:26, length 03:53:05...
Found pre-gap: 00:02:56
Found 40 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 19 (AUDIO): start 53:44:31, length 02:26:02...
Found pre-gap: 00:02:58
Found 47 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.
Analyzing track 20 (AUDIO): start 56:10:33, length 02:51:05...
Found pre-gap: 00:02:55
Found 93 Q sub-channels with CRC errors.
Control nibbles of track match CD-TOC settings.

Reading of toc data finished successfully.

HTOA ripping on non HTOA capable drives

Whipper is calculating other (matching) CRCs than EAC on drives that don't "officially" support HTOA. This could give the wrong impression of a correct rip.

ASUS DRW-24B1ST (non HTOA drive)

whipper log:

00:
Filename: Queens of the Stone Age/Queens of the Stone Age - 2002 - Songs for the Deaf/00 - Hidden Track One Audio.flac
Peak level: 0.853668
Extraction speed: 2.6 X
Extraction quality: 80.42 %
Test CRC: 70A8C7A7
Copy CRC: 70A8C7A7
Status: Copy OK

EAC log:

 Selected range   (Sectors 0-6976)

 Filename qotsaeacasus.wav

 Suspicious position 0:01:30 - 0:01:31

 Peak level 85.3 %
 Extraction speed 0.1 X
 Range quality 97.1 %
 Copy CRC 5F625FEB
 Copy finished

 There were errors

Plextor PX-W2410A (HTOA drive)

whipper log:

00:
Filename: Queens of the Stone Age/Queens of the Stone Age - 2002 - Songs for the Deaf/00 - Hidden Track One Audio.flac
Peak level: 0.853699 %
Extraction speed: 8.3 X
Track quality: 100.00 %
Test CRC: 8FF3CE7F
Copy CRC: 8FF3CE7F
Status: Copy OK

EAC log:

 Selected range   (Sectors 0-6976)

 Filename qotsaeacplextor.wav

 Peak level 85.3 %
 Extraction speed 8.2 X
 Range quality 100.0 %
 Copy CRC 8FF3CE7F
 Copy OK

 No errors occurred

GPG signatures for source validation

As we all know, today more than ever before, it is crucial to be able to trust our computing environments. One of the main difficulties that package maintainers of Linux distributions face, is the difficulty to verify the authenticity and the integrity of the source code.

The Arch Linux team would appreciate it if you would provide us GPG signatures in order to verify easily and quickly of your source code releases.

Overview of the required tasks:

Additional Information:

Thanks.

pygobject_register_sinkfunc is deprecated

In order to prepare for never version where this gets removed, you should possibly fix it? However it still works. Using ArchLinux.

FreeDB identifies disc as Scooter / 20 Years Of Hardcore CD 01
** Message: pygobject_register_sinkfunc is deprecated (GstObject)
Creating output directory /home/arch/Music/Unknown/Unknown Artist/kKrMj0RknVuwLKBn1Om8hwcJbu0-

add manpage

What form this takes needs to come after we remove python-command.

Minimal makedepends for building

As I'm currently trying to package whipper for the AUR, I narrowed down the smallest set of requirements for building it successfully:

  • python2-gobject2
  • python2-musicbrainzngs
  • python2-setuptools

Those were enough to correctly build it from a git checkout. I can post the rest of the PKGBUILD/build process is there is interest, but I'm waiting feedback on #16 to get it to run :)

Cheers

Don't allow ripping without an explicit offset, and make pycdio a required dependency

Right now, if you don't set the offset for a drive, the ripping process with proceed with just a warning ("WARNING: using default offset 0").

It would be better to force the user to set it explicitly (either using rip offset find, or manually setting it in the config file), and error out if it's not set.

In line with this it would be good to also make the pycdio dependency a required one rather than optional. It would additionally allow to simplify some code (by no longer having to handle pycdio being present or not), and make it more user friendly (just install from the package system and you have everything you need).

ImportError: No module named log

I receive this error in the latest version when starting the rip command:

Traceback (most recent call last):
  File "/usr/local/bin/rip", line 11, in <module>
load_entry_point('whipper==0.3.0', 'console_scripts', 'rip')()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 565, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2589, in load_entry_point
return ep.load()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2249, in load
return self.resolve()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2255, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/local/lib/python2.7/dist-packages/whipper-0.3.0-py2.7.egg/morituri/rip/main.py", line 9, in <module>
from morituri.common import log, logcommand, common, config, directory
  File "/usr/local/lib/python2.7/dist-packages/whipper-0.3.0-py2.7.egg/morituri/common/log.py", line 27, in <module>
from morituri.extern.log import log as externlog
ImportError: No module named log

Release, Tags, NEWS?

Hi,

I’ve seen that the setup.py file now reports 0.3. Do you consider this as a release?

If so, you should update the NEWS file and some other things like that, tag the version, and release it in the corresponding tab. ;)

Else, avoid bumping that number until release, because sane tools building from git (see the ArchLinux AUR PKGBUILD for instance) use the tag as base version number, and will report v0.2.3 currently, while they have apparently been a 0.2.4 and now 0.3. ;)

Other than that, keep doing this great work! :)

[Tracking issue] patches from IA's morituri fork to rebase to whipper

This is a tracking issue (for me) to contribute back the following changes that I made to our/my private fork of morituri. Context: I use morituri as-a-library (kind of), so we never invoke the main ripping code. This led me to having to shuffle a lot of code around, so in the end I'll also want to see if we can make whipper available as a library in a nice way. That involves removing various calls to exit(), for example.

  • ARv2 support (using a faster tool): #18 (See PR #37)
  • ARv2 support in the report/log files: #18
  • [WIP] Data track support
  • Logging improvements (remove flog)
  • cdparanoia error parsing
  • Ripping tracks only once, based on availability in AccurateRip
  • Ripping tracks in fast mode, based on availability in AccurateRip
  • Remove gstreamer dependencies by using 'flac' for encoding (the tool)
  • shardz had a tool for peak detection, IIRC

Some of these features you may not want to merge even if rebased, because they may conflict with morituri's original goals (rip perfect, always twice, etc).

I will add expected dates (for PRs) soon, and update the issue accordingly.

On Arch Linux, CDDB does not know how to install morituri.

Checking device /dev/sr0
CDDB disc id: 84081a0c
MusicBrainz disc id VJ3Z4dFI8V3VWPBbiV9J0g0xqjk-
MusicBrainz lookup URL https://musicbrainz.org/cdtoc/attach?toc=1+12+155706+150+2956+15144+25747+40355+61695+77412+87641+106201+112959+123863+136355&tracks=12&id=VJ3Z4dFI8V3VWPBbiV9J0g0xqjk-
Disc duration: 00:34:34.080, 12 audio tracks
Continuing without metadata
Submit this disc to MusicBrainz at the above URL.

Could not import python module 'CDDB'
This module is part of python-CDDB.
See http://cddb-py.sourceforge.net/ for more information.

On Arch Linux, CDDB does not know how to install morituri.
Please file a bug at:
http://thomas.apestaart.org/morituri/trac/newticket?summary=DEP%3A%20CDDB%2C%20Arch%20Linux
with instructions on how to install the dependency so we can add it.

Please install CDDB and try again.

You can confirm it is installed by starting Python and running:
import CDDB

cdda2wav from cdrtools instead of cdparanoia

I would suggest to use cdda2wav with -paranoia switch instead of cdparanoia.

cdparanoia is not actively developed, cdda2wav is. I used abcde for ripping, which gives you the option of cdparanoia or cdda2wav, and the latter gave much better results (quicker, less error-prone).

can't find accuraterip-checksum binary in morituri-uninstalled mode

In morituri-uninstalled mode, I am now getting

$ rip offset find
Checking device /dev/cdrom
Trying read offset 6 ...                      
Traceback (most recent call last):            1 %      
  File "/home/kevmitch/src/whipper/morituri/extern/task/task.py", line 511, in c
    callable(*args, **kwargs)
  File "/home/kevmitch/src/whipper/morituri/common/checksum.py", line 292, in _arc
    self._wave, self._v2)
  File "/home/kevmitch/src/whipper/morituri/program/arc.py", line 22, in accuraterip_checksum
    stdout=PIPE, stderr=PIPE)
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

This is fixed by copying the accuraterip-checksum binary to the bin directory. Trouble is, I can't figure out how to get the build system to do that.

Remove gstreamer dependency

It would be nice to rip out the gstreamer dependency. This means:

  1. Writing code for peak calculation using sox (we have this ready)
  2. Encoding using the flac tool (we have this ready)
  3. AR calculation using the accuraterip_checksum tool (we have this, kinda)

For 3 - I will only for V1 first. Adding V2 support is relatively easy, but that should be done separately.

Error selecting Drive for ripping

If I run this command (cause I've 2 drives) gives this error. Af far i know -d let me select the drive.

rootsandculture@rootsandculture-X58A-UD3R:~$ rip cd rip -d /dev/sr1
Usage: rip cd rip

rip: error: no such option: -d

If I run "rip offset find -d /dev/sr1" ir runs ok
Checking device /dev/sr1
Trying read offset 6 ...
Ripping track 1 with read offset 6 0 %

Grab cover art

I'd love to see whipper to automatically grab the album art from musicbrainz like beets with the FetchArt plugin is able to. This step shouldn't be to hard as whipper already detects the correct musicbrainz album ID und thus the corresponding URL. As Beets is also written in Python it's probably possible to get the source code from there.

NameError: global name 'musicbrainz' is not defined

I have the following error when trying to run whipper after building the latest checkout:

# rip -h
Traceback (most recent call last):
  File "/usr/bin/rip", line 41, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 39, in main
    musicbrainz.set_useragent("morituri", configure.version,
NameError: global name 'musicbrainz' is not defined

No matter what I try (installing python2-musicbrainz2 besides python2-musicbrainzngs...), it doesn't change anything. Suspecting 89f3ba3 to be at play here :)

This is on Arch Linux, running in a clean x64 chroot used for the build (I'm trying to package whipper for the AUR).

Thanks for your work on reviving morituri!

Allow user submission to the AccurateRip database

AccurateRip URL http://www.accuraterip.com/accuraterip/a/6/8/dBAR-012-000e686a-008a4eb8-84081a0c.bin
Album not found in AccurateRip database
Track  1: rip NOT accurate (not found)             [e5f61ed9], DB [notfound]
Track  2: rip NOT accurate (not found)             [bcb9ac0a], DB [notfound]
Track  3: rip NOT accurate (not found)             [db4767bf], DB [notfound]
Track  4: rip NOT accurate (not found)             [fe83e31d], DB [notfound]
Track  5: rip NOT accurate (not found)             [f44f789e], DB [notfound]
Track  6: rip NOT accurate (not found)             [cbf7fbcc], DB [notfound]
Track  7: rip NOT accurate (not found)             [c7a348d6], DB [notfound]
Track  8: rip NOT accurate (not found)             [f412d33b], DB [notfound]
Track  9: rip NOT accurate (not found)             [6013ff9a], DB [notfound]
Track 10: rip NOT accurate (not found)             [3d75a847], DB [notfound]
Track 11: rip NOT accurate (not found)             [dbd7661f], DB [notfound]
Track 12: rip NOT accurate (not found)             [89807686], DB [notfound]

Can we add rips to the database to help it grow?

ERROR: stopping task which is already stopped

When ripping a certain track, I get this error:

ERROR: stopping task which is already stopped
  File "/usr/bin/rip", line 11, in <module>
    load_entry_point('whipper==0.3.0', 'console_scripts', 'rip')()
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 22, in main
    ret = c.parse(sys.argv[1:])
  File "/usr/lib/python2.7/site-packages/morituri/rip/main.py", line 89, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/lib/python2.7/site-packages/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/usr/lib/python2.7/site-packages/morituri/rip/cd.py", line 174, in do
    self.doCommand()
  File "/usr/lib/python2.7/site-packages/morituri/rip/cd.py", line 482, in doCommand
    ripIfNotRipped(i + 1)
  File "/usr/lib/python2.7/site-packages/morituri/rip/cd.py", line 414, in ripIfNotRipped
    number, len(self.itable.tracks), extra))
  File "/usr/lib/python2.7/site-packages/morituri/common/program.py", line 603, in ripTrack
    runner.run(t)
  File "/usr/lib/python2.7/site-packages/morituri/extern/task/task.py", line 479, in run
    self._loop.run()
  File "/usr/lib/python2.7/site-packages/morituri/extern/task/task.py", line 511, in c
    callable(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/morituri/extern/task/gstreamer.py", line 151, in stop
    task.Task.stop(self)
  File "/usr/lib/python2.7/site-packages/morituri/extern/task/task.py", line 154, in stop
    import traceback; traceback.print_stack()

It happens multiple times, when the ripper retries.

CD-TEXT issue

I tried to rip a CD that oviously contains CD-TEXT. I got this error message:

...
Scanning indexes of session 1... (2 of 2) ...  98 %
Scanning indexes of session 1... (2 of 2) ...  99 %
Scanning indexes of session 1... (2 of 2) ... 100 %

Scanning indexes of session 1... (2 of 2) ... 100 %

Traceback (most recent call last):
  File "/usr/local/bin/rip", line 37, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/main.py", line 40, in main
    ret = c.parse(argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/main.py", line 118, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/usr/local/lib/python2.7/site-packages/morituri/common/logcommand.py", line 62, in parse
    command.Command.parse(self, argv)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/usr/local/lib/python2.7/site-packages/morituri/rip/cd.py", line 128, in do
    self.ittoc.getMusicBrainzDiscId(), self.device, offset)
  File "/usr/local/lib/python2.7/site-packages/morituri/common/program.py", line 177, in getTable
    runner.run(t)
  File "/usr/local/lib/python2.7/site-packages/morituri/extern/task/task.py", line 490, in run
    raise TaskException(task.exception, message=msg)
morituri.extern.task.task.TaskException: (ProgramError('Reading of CD-TEXT data failed.',), None)

Maybe it's possible to simply omit tracks in this format before trying to read?

It is this CD (maybe this helps): https://musicbrainz.org/release/75fab53f-68a1-4f37-ab5d-d71a316e84ad

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.