Update of /cvsroot/freevo/freevo/src/audio/plugins
In directory sc8-pr-cvs1:/tmp/cvs-serv1954/src/audio/plugins
Added Files:
cdbackup.py
Log Message:
Added a working cd backup plugin.
I was able to rip songs succesfully after making some minor changes.
>From the submitted code I made the following changes:
o Moved all command-line tools to config
o Put defaults in freevo_config for encoding parameters.
o Removed all CDDB code, we only use mmpython now.
Current issues:
o As far as I can tell, mmpython is swapping the artist and the album
o No progress or information of any kind. I'll probably put something into
the idle bar to at least make it clear something is happening.
Still, it's very complete and works very well so far. I put --preset standard as the
default encoding style for lame, which is reasonable, though not what I would use.
--- NEW FILE: cdbackup.py ---
#if 0 /*
# -----------------------------------------------------------------------
# cdbackup.py - CD Backup plugin for ripping/backing up CDs to
# your hard drive
# -----------------------------------------------------------------------
# $Id: cdbackup.py,v 1.1 2003/07/01 03:52:41 outlyer Exp $
#
# Revision 1.1 2003/06/25 17:53:35 cornejo
# Changed from MainMenuPlugin to be an ItemPlugin
# When ripping to .mp3, made the temporary .wav file reside in /tmp instead of user
defined directory
# Changed get_formatted_cd_info to use mmpython instead of my own function.
#
#
# Notes: This is the cdbackup module which can be accessed from the audio menu
# by hitting 'e' or enter (not return) whilst a CD is selected.
#
# It allows you to backup CDs as .wav files or as .mp3s.
#
# To Activate Plugin, add the following to local_conf.py:
# plugin.activate('audio.cdbackup')
#
# Todo:
# Add a status bar showing progress
# Parse the output of cdparanoia and lame to determine status of rip, mp3 conversion
# Add more flexibilty in adding id3 (id3v2) tags
# Add ogg encoding
# For encoding parameters, make choices dynamic/selectable from menu instead of only
local_conf.py
# maybe just use local_conf.py parameters as defaults.
# Be able to stop ripping once it's started.
# Be able to select individual songs for ripping.
# There is slight delay before menu opens up after being selected from main menu,
# add a hourglass or some other notification that its loading.
# Albums with more than one Artist aren't handled very well.
# -----------------------------------------------------------------------
# $Log: cdbackup.py,v $
# Revision 1.1 2003/07/01 03:52:41 outlyer
# Added a working cd backup plugin.
#
# I was able to rip songs succesfully after making some minor changes.
#
# From the submitted code I made the following changes:
#
# o Moved all command-line tools to config
# o Put defaults in freevo_config for encoding parameters.
# o Removed all CDDB code, we only use mmpython now.
#
# Current issues:
#
# o As far as I can tell, mmpython is swapping the artist and the album
# o No progress or information of any kind. I'll probably put something into
# the idle bar to at least make it clear something is happening.
#
# Still, it's very complete and works very well so far. I put --preset standard as the
# default encoding style for lame, which is reasonable, though not what I would use.
#
# Revision 1.0 2003/06/09 21:12:58 cornejo
# o Initial Revision - currently only supports ripping a CD to the hard drive
# o in either .wav or .mp3.
# o Uses directory and file naming as obtained by CDDB CD Artist, Album, and track
info.
# o local_conf.py parameter is used to determine directory structure and file naming
scheme.
# o local_conf.py parameter is also used for lame encoding parameters, and id3 tagging
info
# o CD Audio detection/identifciation code was copied/modified from rom_drives.py
who's Author=dischi
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002 Krister Lagerstrom, et al.
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# 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 2 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 MER-
# CHANTABILITY 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.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ----------------------------------------------------------------------- */
#endif
import os
import time
import string
# Configuration file. Determines where to look for AVI/MP3 files, etc
import config
# The menu widget class
import menu
# The RemoteControl class, sets up a UDP daemon that the remote control client
# sends commands to
import rc
from gui.AlertBox import AlertBox
from gui.PopupBox import PopupBox
from gui.ConfirmBox import ConfirmBox
#from plugin import MainMenuPlugin
#from plugin import ItemPlugin
import plugin
from item import Item
#Import utitlity for it's directory/filename handling functions
import util
import skin
skin = skin.get_singleton()
#os has functions to execute files, e.g. to be used for running "cdparanoia" to rip
CDs and lame to encode.
import os
import sys
#used after getting the file descriptor???
from fcntl import ioctl
#Used to call cdrom open def
#Need this to prevent the long CD ripping time from stalling Freevo until the rip is
finished.
#See URL below for learning to use threads
#http://starship.python.net/crew/aahz/OSCON2001/threads.pdf
import threading
#Import re (regular exprssion) to be able to search strings, and split strings, etc...
import re
#Included to be able to access the info for Audio CDs
import mmpython
# Set to 1 for debug output
DEBUG = config.DEBUG
TRUE = 1
FALSE = 0
menuwidget = menu.get_singleton()
killflag = 0
song_names = []
class main_backup_thread(threading.Thread):
device = None
rip_format = ''
def __init__(self, rip_format, device=None):
threading.Thread.__init__(self)
self.device = device
self.rip_format = rip_format
def run(self, rip_format='mp3'):
if self.rip_format == 'mp3' :
self.cd_backup_threaded(self.device, rip_format='mp3')
else:
self.cd_backup_threaded(self.device, rip_format='wav')
def cd_backup_threaded(self, device, rip_format='mp3'):
print 'cd_backup_threaded function, rip_format = %s' %rip_format
rip_format = rip_format
album = 'default_album'
artist = 'default_artist'
genre = 'default_genre'
dir_audio_default = "dir_audio_default"
path_head = ''
#Get the artist, album and song_names
(artist, album, genre, song_names) = self.get_formatted_cd_info(device)
print 'artist = %s' %artist
print 'album = %s' %album
print 'genre = %s' %genre
#Figuring out this little rascal took me a while,
# the pleasures of learning a new language.
# Anyhow, Python is a really kick butt language as I'm quickly finding out.
dir_audio = config.DIR_AUDIO[0][1]
user_rip_path_prefs = { 'artist': artist,
'album': album,
'genre': genre }
path_list = re.split("\\/", config.CD_RIP_PN_PREF)
#CD_RIP_PN_PREF = '%(genre)s/%(artist)s/%(album)s/%(song)s'
#Get everything up to the last "/"
if len(path_list) != 0:
print 'path_list != 0'
for i in range (0, len(path_list)-1 ):
path_head += '/' + path_list[i]
print 'This is path_head : %s' %path_head
#path_tail_temp is everything to the right of the last '/' which is the last
#element in path_list.
print 'len(path_list)=%i' %len(path_list)
path_tail_temp = '/' + path_list[len(path_list)-1]
#If no directory structure preferences were given use default dir structure
if len(path_list) == 0:
pathname = dir_audio + "/" + artists + "/" + album + "/"
#Else use the preferences given by user
else:
path_temp = dir_audio + path_head
pathname = path_temp % user_rip_path_prefs
print 'This is path_temp : %s' %path_temp
print 'This is pathname : %s' %pathname
try:
os.makedirs(pathname, 0777)
except:
print 'Directory %s already exists' %pathname
#pass
print 'Starting cd_backup_wav'
cdparanoia_command = []
length=len(song_names)
print 'Length of songnames = %s' %length
for i in range (0, len(song_names)):
#Keep track of track#
track = i +1
# CD_RIP_PATH = '%(artist)s/%(album)/%(song)s'
#Add the song and track key back into user_rip_path_prefs to be used in
the song name
#as specified in CD_RIP_PN_PREF. The song name was previously not set
#so had to wait until here to add it in.
user_rip_path_prefs = { 'artist': artist,
'album': album,
'genre': genre,
'track': track,
'song': song_names[i] }
path_tail = path_tail_temp % user_rip_path_prefs
print 'path_tail %s' % path_tail
print 'Before Command = %s' %cdparanoia_command
print 'stri(i)= %s' %i
#If rip_format is mp3, then copy the file to /temp/track_being_ripped.wav
if rip_format=='mp3' or rip_format== 'MP3':
pathname_cdparanoia = '/tmp'
path_tail_cdparanoia = '/track_being_rippped'
#Otherwise if it's going to be a .wav just use the the users preferred
directory and filename.
#i.e. don't bother putting into /tmp directory, just use directory and
filename of final destination.
else:
pathname_cdparanoia = pathname
path_tail_cdparanoia = path_tail
#Build the cdparanoia command to be run
#cdparanoia_command = '/usr/local/freevo/runtime/apps/cdparanoia -s ' \
cdparanoia_command = config.CDPAR_CMD + ' -s ' \
+ str(i+1) \
+' "' \
+ pathname_cdparanoia \
+ path_tail_cdparanoia \
+ '.wav"' \
print 'After Command = %s' %cdparanoia_command
#Have the OS execute the CD Paranoia rip command
os.system(cdparanoia_command)
#Build the cdparanoia command to be run if mp3 format is selected
print 'rip_format = %s' %rip_format
if rip_format=='mp3' or rip_format== 'MP3':
artist_quoted = '\"' + artist + '\"'
album_quoted = '\"' + album + '\"'
genre_quoted = '\"' + genre + '\"'
song_name_quoted = '\"' + song_names[i] + '\"'
user_rip_path_prefs_quoted = { 'artist' : artist_quoted,
'album': album_quoted,
'genre' : genre_quoted,
'song' :
song_name_quoted,
'track' : track }
id3_tag_opts = ' '
id3_tag_opts_temp = config.CD_RIP_ID3_TAG_OPTS
id3_tag_opts += id3_tag_opts_temp % user_rip_path_prefs_quoted
id3_tag_opts += ' '
print 'The id3_tag_opts = %s' %id3_tag_opts
lame_command = config.LAME_CMD + ' -h ' \
+ config.CD_RIP_LAME_OPTS \
+ id3_tag_opts \
+ ' \'' \
+ pathname_cdparanoia \
+ path_tail_cdparanoia \
+ '.wav\'' \
+ ' \'' \
+ pathname \
+ path_tail \
+ '.mp3\'' \
print 'lame_command = %s' %lame_command
os.system(lame_command)
#Remove the .wav file.
rm_command = 'rm \'' + pathname_cdparanoia + path_tail_cdparanoia +
'.wav' + '\''
print 'rm_command = %s' %rm_command
os.system(rm_command)
#Flash a popup window indicating copying is done
popup_string="Finished Copying CD"
pop = PopupBox(text=popup_string)
pop.show()
time.sleep(4)
pop.destroy()
def get_formatted_cd_info(self, device):
cd_info = mmpython.parse(device)
"""
These are the attribues/info available from mmpython/audioinfo.py
Attributes of cd_info:
title: The Hits
artist: Garth Brooks
type: audio cd
url: file:///dev/scd0
id: 290f9412_18
Attributes of cd_info.track:
title: That Summer
artist: Garth Brooks
samplerate: 44.1
length: 288
codec: PCM
trackno: 17
trackof: 18
album: The Hits
genre: blues
MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
'date', 'keywords', 'country', 'language', 'url']
AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
'bitrate', 'language']
MUSICCORE = ['trackno', 'trackof', 'album', 'genre']
"""
"""
#Get the Artist's name(could be more than one) and Album name
#Also, get rid of the space at the end of the Artists name, and before the
Album name
# Artist name and album are returned as "Artist / Album"
# -note the "space slash space" between Artist and Album
artist_album = re.split(" \\/ ", cd_info)
artist =''
album =''
if (cd_info != ''):
#Is there more than one Artist on this CD?
artist_album_length = len(artist_album)
if artist_album_length > 1:
for i in range (0, len(artist_album) - 1):
#Are we at the last Artist on the album
if (i == (len(artist_album) - 2)):
artist += artist_album[i]
else :
artist += artist_album[i] + '-'
#The album is the last element in the list
album = artist_album[len(artist_album)-1]
#If there is only 1 Artist, then the list is only 2 elements
elif (artist_album_length == 1 ):
artist = artist_album[0]
album = artist_album[1]
"""
print 'cd_info.title : %s' %cd_info.title
#Check if CDDB data failed -is there a better way to do this?
#Give some defaults with a timestamp to uniqueify artist and album names.
#So that subsequent CDs with no CDDB data found don't overwrite each other.
if ((cd_info.title == None) and (cd_info.artist == None)):
print '*************No CDDB data returned from MMPYTHON'
# Creates a string which looks like "28-Jun-03-10:16am"
# http://www.python.org/doc/current/lib/module-time.html
current_time = time.strftime('%d-%b-%y-%I:%M%P')
print 'The current time is: %s' %current_time
artist ='Unknown Artist ' + current_time + ' - RENAME'
album ='Unknown CD Album ' + current_time + ' - RENAME'
genre ='Other'
#Flash a popup window indicating copying is done
popup_string="CD info not found!\nMust manually rename files\nwhen
finished ripping"
pop = PopupBox(text=popup_string)
pop.show()
time.sleep(7)
pop.destroy()
#If valid data was returned from mmpython/CDDB
else:
album = self.replace_special_char(cd_info.title, '-')
artist = self.replace_special_char(cd_info.artist, '-')
genre = self.replace_special_char(cd_info.tracks[0].genre, '-')
song_names = []
print 'About to print all tracks info'
for track in cd_info.tracks:
print 'track = %s' %track
song_names.append(self.replace_special_char(track.title, '-'))
print 'album_temp : %s' %album
print 'artist_temp : %s' %artist
print 'genre_temp : %s' %genre
for song in song_names:
print 'song_name : %s' %song
return [artist, album, genre, song_names]
#This function gets rid of the slash, '/', in a string, and replaces it with
join_string
def slash_split(self, string, join_string = '-'):
split_string= re.split(" \\/ ", string)
rejoined_string = ''
#Were there any splits on '/'?
if len(split_string) > 1:
for i in range (0, len(split_string)):
#Are we at the last slash
if (i == (len(split_string) - 1)):
rejoined_string += split_string[i]
#if not at the last slash, keep adding to string the join_string
else :
rejoined_string += split_string[i] + join_string
#If there are no slashes , then the list is only 1 element long and there is
nothing to do.
else:
rejoined_string = string
return rejoined_string
#Function to get rid of funky characters that exist in a string
#so that when for example writing a file to disk, the filename
#doesn't contain any special reserved characters.
#This list of special_chars probably contains some characters that are okay.
def replace_special_char(self, string, repl='-'):
# Regular Expression Special Chars = . ^ $ * + ? { [ ] \ | ( )
special_chars = [ '\"', '\`', '\\\\', '/' ]
"""
special_chars = [ '~', '!', '@', '\\$', '%', \
'\\*', '\\|', ':', \
'\"', '\\?', '\`', '\\\\', \
';', "\'", '/' ]
"""
#'~', '!', '@', '#', '\\$', '%', '\\^', '&', \
#'\\*', '\\(', '\\)', '\\[', '\\]', '\\+', '\\|',
'\\{', '}', ':', \
#'\"', '<', '>', '\\?', '\`', '=', '\\\\', \
#';', "\'", '/' ]
new_string = string
num = 0
for j in special_chars:
pattern = j
try:
#A few of the special characters get automatically converted to a
different char,
#rather than what is passed in as repl
if (pattern == '\''):
(new_string, num) = re.subn(pattern, '', new_string, count=0)
elif (pattern == '/'):
(new_string, num) = re.subn(pattern, '\\\\', new_string, count=0)
#elif: (pattern == '('):
# (new_string, num) = re.subn(pattern, '<', new_string, count=0)
#elif: (pattern == ')'):
# (new_string, num) = re.subn(pattern, '>', new_string, count=0)
else:
(new_string, num) = re.subn(pattern, repl, new_string, count=0)
except:
print 'excepted trying to call re.subn'
return new_string
# See the following for how to use DiscID and CDDB.py
# http://cddb-py.sourceforge.net/CDDB/README
"""DiscID return variables
---------------------------------
DiscID.disc_id()
disc_id
disc_id[0] = DiscID
disc_id[1] = # of Songs on CD
CDDB return variables
query()
status = 200
category = classical, etc....
disc-id = DiscID
title = Title of CD
...or for multiple matches....
...
An Array of the following is returned -each element is the info for a different CD
status = 210 or 211 (210, 211 are for multiple matches)
category = classical, etc....
disc-id = DiscID
title = Title of CD
read()
status = 210 (success), !210 = Access Denied or No Match
info = cd_info, Access Denied response, or nothing
cd_info = Includes Track Titles, can access as
cd_info[TTITLE] upto
cd_info[TTITLE + # of songs)
"""
# The following ss needed in local_conf.py to get this plugin to show up
# plugin.activate('audio.cdbackup')
#
#
class PluginInterface(plugin.ItemPlugin):
"""
Plugin to rip and burn MP3s/CDs/Movies
"""
artist = ''
album = ''
song_names = []
device = ''
#def __init__(self):
# plugin.ItemPlugin.__init__(self)
def actions(self, item):
self.item = item
try:
if (self.item.display_type == 'audio'):
self.device = self.item.devicename
print 'devicename = %s' %self.device
return [ ( self.create_backup_menu, 'Rip the CD to the hard drive',
'Get CDs available for ripping') ]
except:
print 'Can not rip, item is not an AudioCD'
return []
def create_backup_menu(self, arg=None, menuw=None):
print 'CD Backup: create_backup_menu'
mm_menu = self.create_backup_items(self.device, menuw=None)
menuwidget.pushmenu(mm_menu)
menuwidget.refresh()
print 'create_backup_menu: %s' %arg
def create_backup_items(self, arg, menuw):
print 'CD Backup: create_backup_items'
items = []
items += [menu.MenuItem('Backup CD to hard drive in .wav format',
self.cd_backup_wav, arg=arg)]
print 'create_backup_items: arg = %s' %arg
items += [menu.MenuItem('Backup CD to hard drive in .mp3 format',
self.cd_backup_mp3, arg=arg)]
"""
items += [menu.MenuItem('TBD-Burn MP3s onto CD in regular CD-Audio format)',
cd_backup_mp3,2)]
items += [menu.MenuItem('TBD-Organize Files',
cd_backup_mp3,2)]
items += [menu.MenuItem('TBD-Backup DVD to Hard Drive',
cd_backup_mp3,2)]
"""
backupmenu = menu.Menu('CD Backup', items, reload_func=self.create_backup_menu)
rc.app(None)
return backupmenu
#CD .wav backup function, starts the main_backup_thread (media manager thread)
def cd_backup_wav(self, arg, menuw=None):
device = arg
#print 'cd_backup_wav: devicename = %s' %devicename
print 'cd_backup_wav: arg = %s' %arg
print 'About to create rip_thread object in .wav def'
rip_thread = main_backup_thread(device=device, rip_format='wav')
print 'About to start .wav thread'
rip_thread.start()
print 'Started .wav thread'
#while rip_thread.isAlive():
#time.sleep(1)
#CD .mp3 backup function, starts the main_backup_thread
def cd_backup_mp3(self, arg, menuw=None):
device = arg
rip_thread = main_backup_thread(device=device, rip_format='mp3')
rip_thread.start()
"""
ID3 Tag Info for ripping to MP3
ID3 tag options:
--tt title
audio/song title (max 30 chars for version 1 tag)
--ta artist
audio/song artist (max 30 chars for version 1 tag)
--tl album
audio/song album (max 30 chars for version 1 tag)
--ty year
audio/song year of issue (1 to 9999)
--tc comment
user-defined text (max 30 chars for v1 tag, 28 for
v1.1)
--tn track
audio/song track number (1 to 255, creates v1.1
tag)
--tg genre
audio/song genre (name or number in list)
--add-id3v2
force addition of version 2 tag
--id3v1-only
add only a version 1 tag
--id3v2-only
add only a version 2 tag
--space-id3v1
pad version 1 tag with spaces instead of nulls
--pad-id3v2
pad version 2 tag with extra 128 bytes
--genre-list
print alphabetically sorted ID3 genre list and exit
"""
-------------------------------------------------------
This SF.Net email sponsored by: Free pre-built ASP.NET sites including
Data Reports, E-commerce, Portals, and Forums are available now.
Download today and enter to win an XBOX or Visual Studio .NET.
http://aspnet.click-url.com/go/psa00100006ave/direct;at.asp_061203_01/01
_______________________________________________
Freevo-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog