2000 #include "config.h" #include #include #include #include #ifdef HAVE_LIBREADLINE #ifdef OLD_READLINE extern "C" { #endif #include #include #ifdef OLD_READLINE } #endif #ifdef HAVE_LIBCURSES #include //stupid curses macros. #undef erase #undef clear #endif #ifdef HAVE_LIBTERMCAP #include #endif #endif //HAVE_LIBREADLINE #include "misc.h" /* Field Length offsets * Tag 3 0-2 * Songname 30 3-32 * Artist 30 33-62 * Album 30 63-92 * Year 4 93-96 * Comment 30 97-126 * or{ * Comment 28 97-124 * zero 1 125 * Tracknum 1 126 * } * Genre 1 127 */ struct s_v11sub { char comment[28]; unsigned char empty; unsigned char tracknum; }; struct s_id3{ char tag[3]; char songname[30]; char artist[30]; char album[30]; char year[4]; union{ char comment[30]; s_v11sub v11; }; // char comment[28]; // unsigned char empty; // unsigned char tracknum; unsigned char genre; }id3; #define NUM_GENRE 148 #define QUIET_PROGRESS 1 << 0 /* 'File ...' output */ #define QUIET_SONG 1 << 1 /* s */ #define QUIET_ARTIST 1 << 2 /* n */ #define QUIET_ALBUM 1 << 3 /* a */ #define QUIET_YEAR 1 << 4 /* y */ #define QUIET_COMMENT 1 << 5 /* c */ #define QUIET_GENRE 1 << 6 /* g */ #define QUIET_TRACK 1 << 7 /* k */ const char *genre_list[NUM_GENRE+1]={ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop", NULL }; void i3info(const char *file,int quiet); void i3remove(const char *file,int quiet); void i3rename(const char *file,int quiet,int test); void i3edit(const char * file, const char * defsongname, const char * defartist, const char * defalbum, const char * defyear, const char * defcomment, const char * deftracknum, const char * defgenre,int quiet); void stredit(const char * name, int maxlen, char * buf); void print_genre_list(int mode); void version() { printf("id3ed v1.10 - mpeg layer 3 file information editor\n"); } void license() { printf("Copyright 1998-2000 Matt Mueller \n"); printf("\n\ This program is free software; you can redistribute it and/or modify\n\ it under the terms of the GNU General Public License as published by\n\ the Free Software Foundation; either version 2 of the License, or\n\ (at your option) any later version.\n\n\ This program is distributed in the hope that it will be useful,\n\ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ GNU General Public License for more details.\n\n\ You should have received a copy of the GNU General Public License\n\ along with this program; if not, write to the Free Software\n\ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"); } void print_help(void){ version(); printf("\ Usage: id3ed [-s songname] [-n artist] [-a album] [-y year] [-c comment]\n\ [-k tracknum] [-g genre] [-q] [-SNAYCKG] [-l/-L] [-r]\n\ [-i] [-v]\n\n\ -q no line interface; only set tags specified on command\n\ line. Use twice to suppress all output except errors.\n\ -SNAYCKG prompt to edit the specified tags only\n\ Other tags can still be set with the -[snaycg] options.\n\ -l/-L display list of genres\n\ -r remove id3 tag from files\n\ -i show current id3 tag only, don't edit\n\ -v output program version/license\n"); } int main(int argc,char ** argv){ int c,quiet=0,q2=0,mode=0; char *songname = NULL, *artist = NULL, *album = NULL, *year = NULL, *comment = NULL, *tracknum = NULL, *genre = NULL; if (argc<2){ print_help(); } else { while (EOF != (c = getopt(argc, argv, "s:n:a:y:c:k:g:qSNAYCKGlLrimMv"))){ switch (c){ case 's': songname = optarg; break; case 'n': artist = optarg; break; case 'a': album = optarg; break; case 'y': year = optarg; break; case 'c': comment = optarg; break; case 'g': genre = optarg; break; case 'k': tracknum = optarg; break; case 'q': #define REALQUIET() {if (!q2) { quiet = 0xffff & ~QUIET_PROGRESS; q2=1;}} #define UNQUIET(b) { REALQUIET(); quiet &= ~b;} if(q2) quiet |= QUIET_PROGRESS; else { REALQUIET(); } break; case 'S': UNQUIET(QUIET_SONG); break; case 'N': UNQUIET(QUIET_ARTIST); break; case 'A': UNQUIET(QUIET_ALBUM); break; case 'Y': UNQUIET(QUIET_YEAR); break; case 'C': UNQUIET(QUIET_COMMENT); break; case 'G': UNQUIET(QUIET_GENRE); break; case 'K': UNQUIET(QUIET_TRACK); break; case 'l': print_genre_list(0); break; case 'L': print_genre_list(1); break; case 'r': mode=1; break; case 'i': mode=2; break; case 'v': version(); license(); break; case ':': case '?': // fprintf(stderr, "Illegal parameters\n"); print_help(); return 1; case 'm': mode=3; break; case 'M': mode=4; break; } } // printf("quiet=%i q2=%i\n",quiet,q2); for (int i=optind;i=w-1){ x=0;y++; }else{ x++; } if (x==0){ if (i==NUM_GENRE-1) break; printf("\n"); } else printf(" "); } printf("\n"); } int agenretoi(const char * g){ int cmpl=g?strlen(g):0; while (cmpl>0 && isspace(g[cmpl-1])) --cmpl;//ignore trailing spaces if (cmpl>0){ int i; char * errpos; for(i=0;i struct ltstr{ bool operator()(const char* s1, const char* s2) const {return strcasecmp(s1, s2) < 0;} }; const char *genre_generator(const char *text,int state){ static set matches; static set::iterator curm=matches.end(); const char *ret; if (state==0){ int i; int l=strlen(text); matches.erase(matches.begin(),matches.end()); for (i=0;i",file);fflush(stdout); } if ((end=lseek(f,-128,SEEK_END))<0){ perror("lseek");return; } if (doread(f,&id3,sizeof(id3),"id3buf"))return; close (f); if (!strncmp(id3.tag,"TAG",3)){ char newname[256]; int track=0; if (id3.v11.empty==0) track=id3.v11.tracknum; sprintf(newname,"%02i-%.*s.mp3",track,(int)sizeof(id3.songname),id3.songname);//##### TODO: handle directories in file, handle invalid chars in songname if ((!quiet) || test){ printf("%s\n",newname); } if (!test){ if (rename(file,newname)) perror("rename");return; } }else if ((!quiet)) printf("(no tag)\n"); } void i3info(const char *file,int quiet){ int f; off_t end; if (doopen(f,file,RDMODE))return; printf("%s: ",file);fflush(stdout); if ((end=lseek(f,-128,SEEK_END))<0){ perror("lseek");return; } if (doread(f,&id3,sizeof(id3),"id3buf"))return; if (!strncmp(id3.tag,"TAG",3)){ if (id3.v11.empty==0) printf("(tag v1.1%s)\n",id3.v11.tracknum?"":"?"); else printf("(tag v1.0)\n"); #define PRINTINFO(f) printf("%s: %.*s\n",#f, (int)sizeof(id3. ## f), id3. ## f) PRINTINFO(songname); PRINTINFO(artist); PRINTINFO(album); PRINTINFO(year); PRINTINFO(comment); if (id3.v11.empty==0) printf("tracknum: %i\n", id3.v11.tracknum); printf("genre: %s(%i)\n\n",(id3.genre1.1)\n"); }else{ hasid3=1;//id3 v1.0 commentsize=30; if (!(quiet&QUIET_PROGRESS)) printf(")\n"); } } } if (defsongname){ memset(id3.songname,0,sizeof(id3.songname)); strncpy(id3.songname,defsongname,sizeof(id3.songname)); } if (defartist){ memset(id3.artist,0,sizeof(id3.artist)); strncpy(id3.artist,defartist,sizeof(id3.artist)); } if (defalbum){ memset(id3.album,0,sizeof(id3.album)); strncpy(id3.album,defalbum,sizeof(id3.album)); } if (defyear){ memset(id3.year,0,sizeof(id3.year)); strncpy(id3.year,defyear,sizeof(id3.year)); } if (defcomment){ memset(id3.comment,0,commentsize); strncpy(id3.comment,defcomment,commentsize); } if (deftracknum){ //memset(id3.tracknum,0,sizeof(id3.tracknum)); id3.v11.empty=0; id3.v11.tracknum = atoi(deftracknum); //strncpy(id3.tracknum,deftracknum,sizeof(id3.tracknum)); } if (defgenre){ id3.genre = agenretoi(defgenre); // unsigned tmp; // sscanf(defgenre,"%u",&tmp); // id3.genre = tmp; } if (!(quiet&QUIET_SONG)) stredit("songname",30,id3.songname); if (!(quiet&QUIET_ARTIST)) stredit("artist",30,id3.artist); if (!(quiet&QUIET_ALBUM)) stredit("album",30,id3.album); if (!(quiet&QUIET_YEAR)) stredit("year",4,id3.year); if (!(quiet&QUIET_COMMENT)) stredit("comment",commentsize,id3.comment); if (hasid3!=1 && !(quiet&QUIET_TRACK)) { char tbuf[3]; sprintf(tbuf, "%i", id3.v11.tracknum); stredit("tracknum", 3, tbuf); id3.v11.empty=0; id3.v11.tracknum=atoi(tbuf); } if (!(quiet&QUIET_GENRE)){ 195 // char sbuf[4]; // sprintf(sbuf,"%i",id3.genre); // stredit("genre",3,sbuf); // id3.genre=atoi(sbuf); genreedit(id3.genre); } if (hasid3){ if (lseek(f,-128,SEEK_END)<0){ perror("lseek");return; } }else{ if (lseek(f,0,SEEK_END)<0){ perror("lseek");return; } } if (dowrite(f,&id3,sizeof(id3),"id3buf"))return; close(f); } . 0