def convert_file(cuefile):
    if not os.path.isfile(cuefile):
        print("Error: argument needs to be a file")
        return
    cuesheet = CueSheet()
    cuesheet.setOutputFormat("%title%", "%offset%")
    with open(cuefile, "r") as f:
        cuesheet.setData(f.read())
    cuesheet.parse()
    timestamps = []
    for track in cuesheet.tracks:
        timestamps.append(datetime.strptime(str(track), "%M:%S:%f"))
    converted = convert_time(timestamps)
    write_timing_file(converted)
示例#2
0
    def __init__(self,
                 cuepath,
                 filepath=None,
                 prefer_codec='flac',
                 ffmpeg_bin='ffmpeg',
                 encoding=None):
        self.prefer_codec = prefer_codec
        self.ffmpeg_bin = ffmpeg_bin

        with open(cuepath, 'rb') as fp:
            self.cuesheet = CueSheet()
            if encoding is None:
                self.cuesheet.setData(bytes2str(fp.read()))
            else:
                self.cuesheet.setData(fp.read().decode(encoding))
            self.cuesheet.setOutputFormat(
                '%performer% - %title%\n%file%\n%tracks%',
                '%performer% - %title%',
            )
            self.cuesheet.parse()
            self.n_tracks = len(self.cuesheet.tracks)
            print(self.cuesheet.output())

        if filepath and isfile(filepath):
            self.filepath = filepath
        else:
            if isfile(self.cuesheet.file):
                self.filepath = self.cuesheet.file
            else:
                filepath = join(dirname(cuepath), self.cuesheet.file)
                if isfile(filepath):
                    self.filepath = filepath
                else:
                    raise IOError("Can't not find file: %s" % self.filepath)

        self.amtime = (stat(self.filepath).st_atime,
                       stat(self.filepath).st_mtime)
    def import_cue(self, path: Path, scening_list: SceningList, out_of_range_count: int) -> None:
        '''
        Imports tracks as scenes.
        Uses TITLE for scene label.
        '''
        from cueparser import CueSheet

        def offset_to_time(offset: str) -> Optional[Time]:
            pattern = re.compile(r'(\d{1,2}):(\d{1,2}):(\d{1,2})')
            match = pattern.match(offset)
            if match is None:
                return None
            return Time(
                minutes      = int(match[1]),
                seconds      = int(match[2]),
                milliseconds = int(match[3]) / 75 * 1000)

        cue_sheet = CueSheet()
        cue_sheet.setOutputFormat('')
        cue_sheet.setData(path.read_text())
        cue_sheet.parse()

        for track in cue_sheet.tracks:
            if track.offset is None:
                continue
            offset = offset_to_time(track.offset)
            if offset is None:
                logging.warning(
                    f'Scening import: INDEX timestamp \'{track.offset}\''
                    ' format isn\'t suported.')
                continue
            start = Frame(offset)

            end = None
            if track.duration is not None:
                end = Frame(offset + TimeInterval(track.duration))

            label = ''
            if track.title is not None:
                label = track.title

            try:
                scening_list.add(start, end, label)
            except ValueError:
                out_of_range_count += 1
示例#4
0
def get_mixes():
    mixes_dir = Path.home() / 'Dropbox' / 'mixes'
    mixes = []
    for filename in sorted(os.listdir(str(mixes_dir))):
        if filename.endswith('mp3'):

            mp3_filename = str(mixes_dir / filename)
            mp3_link = _get_dropbox_link(filename)
            name = filename[:-4]
            print(name)

            parts = name.split('-')
            if len(parts) > 1:
                anchor = parts[1]
            else:
                anchor = parts[0]
            anchor = anchor.strip().replace(' ', '-').replace('-[unmixed]', '').replace(',', '').lower()

            duration = _to_minutes(MP3(mp3_filename).info.length)

            cue_filename = str(mixes_dir / f'{name}.cue')
            tracks = []
            cue_link = None

            if os.path.exists(cue_filename):
                cue_link = _get_dropbox_link(name + '.cue')
                cuesheet = CueSheet()
                cuesheet.setOutputFormat('%performer% - %title%\n%file%\n%tracks%', '%performer% - %title%')
                with open(cue_filename, encoding='latin1') as f:
                    cuesheet.setData(f.read())
                cuesheet.parse()
                tracks = cuesheet.tracks

            mixes.append({
                'name': name,
                'anchor': anchor,
                'tracks': tracks,
                'duration': duration,
                'mp3_link': mp3_link,
                'cue_link': cue_link,
            })

    return mixes
示例#5
0
def main():
    args = parser.parse_args()
    new_foldername = copy_dir(args.foldername)
    for root, dirs, files in os.walk(new_foldername):
        # keep a list of all cues and flacs
        flac_filenames = []
        cue_filenames = []
        thumbnail_filename = None
        for name in files:
            if fnmatch(name, "*.flac") or fnmatch(name, ".m4a") or fnmatch(
                    name, '.wma'):
                flac_filenames.append(os.path.join(root, name))
            if fnmatch(name, "*.cue"):
                cue_filenames.append(os.path.join(root, name))
            if fnmatch(name, "*.jpg"):
                thumbnail_filename = os.path.join(root, name)
        # we should now have exactly one flac and one cue file
        if len(flac_filenames) == 1 and len(cue_filenames) == 1:

            ps = subprocess.Popen(('cuebreakpoints', cue_filenames[0]),
                                  stdout=subprocess.PIPE)
            subprocess.check_output(('shnsplit', '-o', 'flac', flac_filenames[0], '-a',
                                     flac_filenames[0].replace(root,'').replace('.flac', ''), '-d', root),
                                    stdin=ps.stdout)
            ps.wait()
            # move the old flac file to the trash
            send2trash(flac_filenames[0])

        if len(cue_filenames)>0:
            cuesheet = CueSheet()
            cuesheet.setOutputFormat('%performer% - %title%\n%file%\n%tracks%', '%title%')
            with open(cue_filenames[0], "r") as f:
                cuesheet.setData(f.read())
            cuesheet.parse()
        else:
            cuesheet = None
        print root
        # convert the other flacs to mp3
        convert_files(root, cuesheet=cuesheet, thumbnail_filename=thumbnail_filename)
示例#6
0
def process_one_set(opts):

    if opts.base is None:
        die("Need to specify basename")

    if opts.debug_mismatch_sizes:
        opts.do_write_no_backup = False
        opts.do_write = True

    if opts.debug_short_cue:
        pass
        #opts.debug = True

    if opts.do_write_no_backup:
        opts.do_write = True

    if (opts.gen_tl == False) and (opts.gen_cue == False):
        opts.gen_tl = True
        opts.gen_cue = True

    if opts.redo_all:
        opts.gen_cue = True
        opts.gen_tl = True
        opts.do_write = True

    if opts.dry_run:
        opts.gen_cue = False
        opts.gen_tl = False
        opts.do_write = False

    ###
    #print(file_base)

    file_base = os.path.basename(opts.base)
    file_base = Path(file_base).stem
    file_base = remove_last_dot(file_base)
    print(file_base)

    file_music = "%s.mp3" % file_base
    opts.output_type = "MP3"

    if os.path.isfile(file_music):
        print("MP3 file found")
    else:
        file_music = "%s.wav" % file_base
        opts.output_type = "WAV"

        if os.path.isfile(file_music):
            print("WAV file found")
        else:
            die("No mp3 or WAV file found. Check for case sensitivity problems."
                )

    #print(file_base)

    opts.file_cue = "%s.cue" % file_base
    opts.file_tl = "%s.txt" % file_base
    opts.file_tl_simple = "%s.tracklist" % file_base
    opts.file_info = "%s.nfo" % file_base
    opts.file_lyrics = "%s.lyrics" % file_base

    if opts.cuefile:
        input_cue = read_file(opts.cuefile)
    else:
        input_cue = read_file(opts.file_cue)

    input_cue = remove_empty_lines(input_cue)

    if opts.debug:
        print("\n\nRead CUE contents:")
        print(input_cue)

    if opts.reload_standard_tracklist:
        opts.tracklist = opts.file_tl

    if opts.tracklist:
        #opts.ignore_tl_num = True
        #opts.file_tl = opts.tracklist
        input_tl = read_file(opts.tracklist)

    else:
        print("Reading tracklist __from CUE file itself__")

        #  TODO: do this by hand

        from cueparser import CueSheet

        template_header = "%performer% - %title%\n%file%\n%tracks%"  # (also can be %format%, %rem%, %songwriter%)
        template_header = "%tracks%"
        template_tracks = "%performer% - %title%"  #(also can be %offset%, %index%, %songwriter%)

        cuesheet = CueSheet()
        #cuesheet.setOutputFormat(args.header, args.track)
        cuesheet.setOutputFormat(template_header, template_tracks)

        #cuesheet.setOutputFormat(args.header, args.track)
        #with open(cuefile, "r") as f:
        #    cuesheet.setData(f.read())

        cuesheet.setData(input_cue)

        import pdb
        try:
            has_error = False
            cuesheet.parse()
        except Exception:
            has_error = True
            print(
                "ERROR: cue sheet error - check frames > 59\n Check also PREGAP 2 entries\n"
            )

        #has_error = True
        if has_error:
            pdb.set_trace()
            cuesheet.parse()
            sys.exit(1)

        input_tl = cuesheet.output()
        opts.ignore_tl_num = False
        opts.has_tl_header = False

    #print(input_tl)

    if opts.debug:
        print("\n\n------")
        print("TL FROM CUE READ:\n %s\n\n" % input_tl)
        #print("CUE READ:\n %s\n\n" % input_cue)

    generate_cue(file_music, input_tl, input_cue)
示例#7
0
class CueCut:
    def __init__(self,
                 cuepath,
                 filepath=None,
                 prefer_codec='flac',
                 ffmpeg_bin='ffmpeg',
                 encoding=None):
        self.prefer_codec = prefer_codec
        self.ffmpeg_bin = ffmpeg_bin

        with open(cuepath, 'rb') as fp:
            self.cuesheet = CueSheet()
            if encoding is None:
                self.cuesheet.setData(bytes2str(fp.read()))
            else:
                self.cuesheet.setData(fp.read().decode(encoding))
            self.cuesheet.setOutputFormat(
                '%performer% - %title%\n%file%\n%tracks%',
                '%performer% - %title%',
            )
            self.cuesheet.parse()
            self.n_tracks = len(self.cuesheet.tracks)
            print(self.cuesheet.output())

        if filepath and isfile(filepath):
            self.filepath = filepath
        else:
            if isfile(self.cuesheet.file):
                self.filepath = self.cuesheet.file
            else:
                filepath = join(dirname(cuepath), self.cuesheet.file)
                if isfile(filepath):
                    self.filepath = filepath
                else:
                    raise IOError("Can't not find file: %s" % self.filepath)

        self.amtime = (stat(self.filepath).st_atime,
                       stat(self.filepath).st_mtime)

    @staticmethod
    def vaildname(name):
        if name in RESERVED_NAME:
            print('Unable to resloving name issue: It`s a reserved name %s' %
                  name)

        vaild = "".join(i if i not in r"\/:*?<>|" else " " for i in name)
        if vaild != name:
            print('Invaild name resloved.',
                  '      "%s"' % name,
                  '  --> "%s"' % vaild,
                  sep='\n',
                  end='\n\n')
        return vaild

    @staticmethod
    def offset(indextime):
        tick = [int(j) for j in indextime.split(':')]
        return tick[0] * 60 + tick[1] + tick[2] * 1e-2

    @staticmethod
    def time_plus_deltatime(start, delta):
        if delta is None:
            return CueCut.offset('99:59:99')
        return CueCut.offset(start) + delta.seconds + delta.microseconds * 1e-6

    def _output(self, trackidx):
        performer = self.cuesheet.tracks[trackidx].performer
        title = self.cuesheet.tracks[trackidx].title
        return join(
            dirname(self.filepath),
            '.'.join([
                self.vaildname(' - '.join(
                    filter(lambda x: x is not None, [performer, title]))),
                self.prefer_codec
            ]),
        )

    def cut(self):
        for idx in range(self.n_tracks):
            self._cut(idx)

    def _cut(self, trackidx):
        track = self.cuesheet.tracks[trackidx]
        output = self._output(trackidx)
        commandline = [
            self.ffmpeg_bin,
            '-hide_banner',  # I reckon you would not want to see the BANNER
            '-y',  # CAUTION: Overwrite by default
            '-i',  # def: Input Stream
            self.filepath,
            '-map_metadata',  # Drop metadata if exists
            '-1',
            '-c:a',  # def: Output Stream Codec
            self.prefer_codec,
            '-ss',  # From where
            '%.2f' % self.offset(track.offset),
            '-to',  # To where
            '%.2f' % self.time_plus_deltatime(track.offset, track.duration),
            '-loglevel',  # Disable massive log record
            'fatal',
            '-metadata',  # def: Metas
            'title=%s' % track.title,
            '-metadata',
            'artist=%s' % (track.songwriter or track.performer, ),
            '-metadata',
            'performer=%s' % track.performer,
            '-metadata',
            'album=%s' % self.cuesheet.title,
            '-metadata',
            'track=%s/%s' % (track.number, self.n_tracks),
            '-metadata',
            'album_artist=%s' % self.cuesheet.performer,
            '-metadata',
            'composer=%s' % self.cuesheet.performer,
            '-write_id3v1',  # Enable ID3V1
            '1',
            '-vn',
            # Disable video stream
            # For some audio file with album image bulit in,
            # may cause the issue
            # `No packets were sent for some of the attached pictures.`
            # which leads to loss of the duration of output
            output,  # def: Output Stream
        ]
        run(commandline, check=True, stderr=PIPE)
        utime(output, self.amtime)
        return 0
示例#8
0
        return ".wav"
    elif cueFormat == "MP3":
        return ".mp3"
    elif cueFormat == "AIFF":
        return ".aiff"
    elif cueFormat == "BINARY":
        return ".bin"
    else:
        return ".wav"


parser = argparse.ArgumentParser()
parser.add_argument("file", help="path to cue file")
args = parser.parse_args()

cuesheet = CueSheet()
cuesheet.setOutputFormat("%performer% - %title%\n%file%\n%tracks%", "%title%")
cuefile = args.file
with open(cuefile, "rb") as f:
    cuesheet.setData(f.read().decode(sys.stdout.encoding))

cuesheet.parse()

ffprobeCmd = "ffprobe -print_format json -show_format -sexagesimal " + cuefile.file

process = Popen(shlex.split(ffprobeCmd), stdout=PIPE, stderr=PIPE)
out = process.communicate()
exit_code = process.wait()

ffprobe_out = json.loads(out[0].decode("utf-8"))
end_time = ffprobe_out["format"]["duration"]