def __init__(self, *a, **kw): Jukebox.__init__(self, *a, **kw) self._json_queue = JsonQueue() self._util = Util(self._json_queue) self._ripper_thread = RipperThread(self, self._json_queue) self._end_of_track = self._ripper_thread.get_end_of_track() self.set_ui_thread(self._ripper_thread) self.session.set_preferred_bitrate(1) # 320 kbps (ostensibly)
class Ripper(Jukebox): _all_processes = [ ] _dot_count = 0 _downloaded = 0.0 _duration = 0 _end_of_track = None _pipe = None _json_queue = None _ripper_thread = None _ripping = False _util = None _meta = {} def __init__(self, *a, **kw): Jukebox.__init__(self, *a, **kw) self._json_queue = JsonQueue() self._util = Util(self._json_queue) self._ripper_thread = RipperThread(self, self._json_queue) self._end_of_track = self._ripper_thread.get_end_of_track() self.set_ui_thread(self._ripper_thread) self.session.set_preferred_bitrate(1) # 320 kbps (ostensibly) def music_delivery_safe(self, \ session, \ frames, \ frame_size, \ num_frames, \ sample_type, \ sample_rate, \ channels): self.rip( session, frames, frame_size, num_frames, sample_type, sample_rate, channels) return num_frames def end_of_track(self, session): Jukebox.end_of_track(self, session) os.rename(self._meta["out_path"] + ".raw.tmp",self._meta["out_path"] + ".raw") self._end_of_track.set() def get_encoders(self): rv = [] for enc,args in self._util.get_encoders().iteritems(): if not enc in ENCODERS: print colored.red("can't find encoder %s" %enc) continue e = ENCODERS[enc]() e.args = args rv.append(e) return rv def rip_init(self, session, track): output_path = self._util.get_output_path(track, escaped = False) print '' print colored.yellow(str(Link.from_track(track))) required = False if self._util.config.download_missing: for enc in self.get_encoders(): if not os.path.exists("%s.%s" %(output_path, enc.suffix)): required = True if not self._json_queue.is_downloaded(Link.from_track(track)): required = True # or os.path.isfile(output_path): with indent(3, quote = colored.white(' > ')): if not required: try: puts('Skipping %s' % output_path) except UnicodeEncodeError: # Non-ASCII characters sys.stdout.write(' > Skipping %s\n' % output_path) return False else: try: puts('Downloading %s' % output_path) except UnicodeEncodeError: # Non-ASCII characters sys.stdout.write(' > Downloading %s\n' % output_path) meta = self._meta = self.prepare_meta(session, track) puts('Track URI: %s' % Link.from_track(track)) try: puts('Album: %s (%i)' % (meta["album"], meta["year"])) except UnicodeEncodeError: sys.stdout.write(' > Album: %s (%i)\n' % (meta["album"], meta["year"])) try: puts('Artist(s): %s' % meta["artist"]) except UnicodeEncodeError: sys.stdout.write(' > Artist(s): %s\n' % meta["artist"]) try: puts('Album artist: %s' % meta["artist"]) except UnicodeEncodeError: sys.stdout.write(' > Album artist(s): %s\n' % meta["artist"]) try: puts('Track: %s-%s. %s' % (meta["disc"], meta["number"], meta["title"])) except UnicodeEncodeError: sys.stdout.write(' > Track: %s-%s. %s \n' \ % (meta["disc"], meta["number"], meta["title"])) rv = True if os.path.exists(meta["out_path"] + ".raw"): print colored.red("raw file exists, skipping download") self._pipe = None rv = -1 else: self._pipe = open(meta["out_path"] + ".raw.tmp","w") self._ripping = True self._dotCount = 0 self._downloaded = 0.0 self._duration = track.duration() return rv def rip_terminate(self, session, track): if self._pipe is not None: self._pipe.close() self._ripping = False def rip(self, session, # the current session frames, # the audio data frame_size, # bytes per frame num_frames, # number of frames in this delivery sample_type, # currently this is always 0, which means 16-bit # signed native endian integer samples sample_rate, # audio sample rate, in samples per second channels): # number of audio channels, currently 1 or 2 self._downloaded += float(frame_size) * float(num_frames) if self._ripping: # 320 kilobits per second # 40 kilobytes per second # duration in milliseconds # 40 bytes per millisecond if not self._pipe: self.end_of_track(session) return total_bytes = float(self._duration) * 40.0 # 100 = 4.41 (don't ask me why) progress_perc = self._downloaded / total_bytes progress_perc = progress_perc * (100.0 / 4.41) progress.bar(range(100)) sys.stdout.write('\r > Progress: %.2f%%' % progress_perc) try: self._pipe.write(frames); except IOError as e: print colored.red("ERROR: %s" %e) os.kill(os.getpid(), 9) def prepare_meta(self, session, track): #out_path = self._util.get_mp3_path(track) out_path = self._util.get_output_path(track, escaped = False) out_path_esc = self._util.get_output_path(track, escaped = False) if self._json_queue.is_starred_track(): album = 'Spotify Starred' else: album = track.album().name() disc = track.disc() number = track.index() title = track.name() year = track.album().year() artist = track.album().artist().name() performers = track.artists() stared = self._json_queue.is_starred_track() if not stared: # download cover image = session.image_create(track.album().cover()) while not image.is_loaded(): time.sleep(0.1) with open('cover.jpg', 'wb') as fp: fp.write(image.data()) return { "out_path": out_path, "out_path_esc": out_path_esc, "album": album, "disc": disc, "number": number, "title": title, "year": year, "artist": artist, "performers": performers, "stared": stared, "genre": None } def encode(self, session, track): # write ID3 data print "\n" + colored.green(str("Encode:")) success = True for enc in self.get_encoders(): if not enc.run(session, self._meta): print colored.red("Error encoding: %s" %enc.suffix) success = False #try: #puts('Moving %s to %s' % ('temp.mp3', mp3_path)) #except UnicodeEncodeError: #sys.stdout.write(' # Moving %s to %s\n' \ #% ('temp.mp3', mp3_path)) ## move mp3 to final directory if not success: print colored.red("Error processing file. Keep raw file") return os.unlink(self._meta["out_path"] + ".raw") if os.path.exists("cover.jpg"): os.unlink("cover.jpg") # delete cover #if not self._json_queue.is_starred_track(): #self._util.shell("rm -f cover.jpg") self._json_queue.mark_as_downloaded(Link.from_track(track))
class Ripper(Jukebox): _all_processes = [ ] _dot_count = 0 _downloaded = 0.0 _duration = 0 _end_of_track = None _pipe = None _json_queue = None _ripper_thread = None _ripping = False _util = None def __init__(self, *a, **kw): Jukebox.__init__(self, *a, **kw) self._json_queue = JsonQueue() self._util = Util(self._json_queue) self._ripper_thread = RipperThread(self, self._json_queue) self._end_of_track = self._ripper_thread.get_end_of_track() self.set_ui_thread(self._ripper_thread) self.session.set_preferred_bitrate(1) # 320 kbps (ostensibly) def music_delivery_safe(self, \ session, \ frames, \ frame_size, \ num_frames, \ sample_type, \ sample_rate, \ channels): self.rip( session, frames, frame_size, num_frames, sample_type, sample_rate, channels) return num_frames def end_of_track(self, session): Jukebox.end_of_track(self, session) self._end_of_track.set() def rip_init(self, session, track): mp3_path = self._util.get_mp3_path(track, escaped = False) print '' print colored.yellow(str(Link.from_track(track))) with indent(3, quote = colored.white(' > ')): if self._json_queue.is_downloaded(Link.from_track(track)) \ or os.path.isfile(mp3_path): try: puts('Skipping %s' % mp3_path) except UnicodeEncodeError: # Non-ASCII characters sys.stdout.write(' > Skipping %s\n' % mp3_path) return False else: try: puts('Downloading %s' % mp3_path) except UnicodeEncodeError: # Non-ASCII characters sys.stdout.write(' > Downloading %s\n' % mp3_path) album = track.album().name() title = track.name() number = str(track.index()).zfill(2) disc = str(track.disc()).zfill(2) year = track.album().year() artists = '' for artist in track.artists(): while not artist.is_loaded(): time.sleep(0.1) artists += artist.name()+' / ' artists = artists.strip().rstrip('/').rstrip() puts('Track URI: %s' % Link.from_track(track)) try: puts('Album: %s (%i)' % (album, year)) except UnicodeEncodeError: sys.stdout.write(' > Album: %s (%i)\n' % (album, year)) try: puts('Artist(s): %s' % artists) except UnicodeEncodeError: sys.stdout.write(' > Artist(s): %s\n' % artists) puts('Album artist: %s' % track.album().artist().name()) try: puts('Track: %s-%s. %s' % (disc, number, title)) except UnicodeEncodeError: sys.stdout.write(' > Track: %s-%s. %s \n' \ % (disc, number, title)) command = 'lame -b 320 -h -r --silent - temp.mp3' p = Popen(command, stdin=PIPE, shell=True) self._all_processes.append(p) self._pipe = p.stdin self._ripping = True self._dotCount = 0 self._downloaded = 0.0 self._duration = track.duration() return True def rip_terminate(self, session, track): if self._pipe is not None: self._pipe.close() self._ripping = False def rip(self, session, # the current session frames, # the audio data frame_size, # bytes per frame num_frames, # number of frames in this delivery sample_type, # currently this is always 0, which means 16-bit # signed native endian integer samples sample_rate, # audio sample rate, in samples per second channels): # number of audio channels, currently 1 or 2 self._downloaded += float(frame_size) * float(num_frames) if self._ripping: # 320 kilobits per second # 40 kilobytes per second # duration in milliseconds # 40 bytes per millisecond total_bytes = float(self._duration) * 40.0 # 100 = 4.41 (don't ask me why) progress_perc = self._downloaded / total_bytes progress_perc = progress_perc * (100.0 / 4.41) progress.bar(range(100)) sys.stdout.write('\r > Progress: %.2f%%' % progress_perc) try: self._pipe.write(frames); except IOError: os.kill(os.getpid(), 9) def rip_id3(self, session, track): # write ID3 data mp3_path = self._util.get_mp3_path(track) if self._json_queue.is_starred_track(): album = 'Spotify Starred' else: album = track.album().name() disc = track.disc() number = track.index() title = track.name() year = track.album().year() artist = track.album().artist().name() performers = '' for performer in track.artists(): performers += performer.name()+', ' performers = performers.strip().rstrip(',') if not self._json_queue.is_starred_track(): # download cover image = session.image_create(track.album().cover()) while not image.is_loaded(): time.sleep(0.1) with open('cover.jpg', 'wb') as fp: fp.write(image.data()) # write id3 data cmd = 'eyeD3'+\ ' --title ' +self._util.shellescape(title)+\ ' --artist ' +self._util.shellescape(performers)+\ ' --album ' +self._util.shellescape(album) if not self._json_queue.is_starred_track(): cmd = cmd\ +' --track ' +str(number) \ +' --disc-num ' +str(disc) \ +' --release-year ' +str(year) \ +' --recording-date ' +str(year) \ +' --add-image cover.jpg:FRONT_COVER' \ +' --text-frame TPE2:'+self._util.shellescape(artist) else: cmd = cmd+ \ ' --text-frame TPE2:' \ +self._util.shellescape('Various Artists') cmd = cmd+' temp.mp3 &>/dev/null' print '' with indent(3, quote = colored.cyan(' # ')): try: puts('Executing %s' % cmd) except UnicodeEncodeError: sys.stdout.write(' # Executing %s\n' % cmd) self._util.shell(cmd) try: puts('Moving %s to %s' % ('temp.mp3', mp3_path)) except UnicodeEncodeError: sys.stdout.write(' # Moving %s to %s\n' \ % ('temp.mp3', mp3_path)) # move mp3 to final directory cmd = 'mv temp.mp3 %s' % mp3_path self._util.shell(cmd) # delete cover if not self._json_queue.is_starred_track(): self._util.shell("rm -f cover.jpg") self._json_queue.mark_as_downloaded(Link.from_track(track))