command line tool for adding ID3 chapters to an MP3 file
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

if an odd-numbered arg is supplied, use it instead of TLEN

see #1

+40 -19
+11 -4
README.md
··· 16 16 17 17 mp3chap file.mp3 0 "chapter 1 is great" 123 "chapter 2 is ok" 456 "chapter 3 is boring" 18 18 19 - The first argument is the path to the MP3 file, then pairs of arguments each containing 20 - a start time in seconds, and the chapter title. 19 + The first argument is the path to the MP3 file, then pairs of arguments each 20 + containing a start time in seconds, and the chapter title. 21 + 22 + It is assumed that each chapter ends where the next one begins, and that the 23 + final chapter ends at the last millisecond of the file (as defined in its 24 + `TLEN` ID3 frame). 25 + 26 + If the file does not contain a `TLEN` ID3 frame, a final time argument must 27 + be supplied (in seconds) which will be used as the end time of the final 28 + chapter. 21 29 22 - It is assumed that each chapter ends where the next one begins, and that the final chapter 23 - ends at the last millisecond of the file (as defined in its `TLEN` ID3 frame). 30 + mp3chap file.mp3 0 "chapter 1 is great" 123 "chapter 2 is ok" 456 "chapter 3 is boring" 789 24 31 25 32 Changes to the ID3 tag in the MP3 file are written out in-place. 26 33
+29 -15
mp3chap.go
··· 62 62 63 63 chaps := make([]Chapter, 0) 64 64 tocchaps := make([]string, 0) 65 + finalEnd := uint64(0) 65 66 66 - for x := 2; x < len(os.Args)-1; x += 2 { 67 + x := 2 68 + for ; x < len(os.Args)-1; x += 2 { 67 69 if x+1 > len(os.Args)-2+1 { 68 70 usage() 69 71 } ··· 80 82 chaps = append(chaps, chap) 81 83 } 82 84 85 + // if there is a final odd arg, use it as the final chapter end 86 + if x < len(os.Args) { 87 + finalEnd, err = strconv.ParseUint(os.Args[x], 10, 32) 88 + if err != nil { 89 + log.Fatal("failed parsing final seconds %#v: %v", os.Args[x], err) 90 + } 91 + } 92 + 83 93 // each chapter ends where the next one starts 84 94 for x := range chaps { 85 95 if x < len(chaps)-1 { ··· 87 97 } 88 98 } 89 99 90 - // and the last one ends when the file does 91 - tlenf := mp3.Frame("TLEN") 92 - if tlenf == nil { 93 - log.Fatal("can't find TLEN frame, don't know total duration") 94 - } 95 - tlenft, ok := tlenf.(*id3v2.TextFrame) 96 - if !ok { 97 - log.Fatal("can't convert TLEN to TextFrame") 98 - } 99 - tlen, err := strconv.ParseUint(tlenft.Text(), 10, 32) 100 - if err == nil { 101 - log.Fatal("can't parse TLEN value %#v\n", tlenft.Text()) 102 - } 100 + if finalEnd == 0 { 101 + // and the last one ends when the file does 102 + tlenf := mp3.Frame("TLEN") 103 + if tlenf == nil { 104 + log.Fatal("can't find TLEN frame, don't know total duration") 105 + } 106 + tlenft, ok := tlenf.(*id3v2.TextFrame) 107 + if !ok { 108 + log.Fatal("can't convert TLEN to TextFrame") 109 + } 110 + tlen, err := strconv.ParseUint(tlenft.Text(), 10, 32) 111 + if err == nil { 112 + log.Fatal("can't parse TLEN value %#v\n", tlenft.Text()) 113 + } 103 114 104 - chaps[len(chaps)-1].endSecs = uint32(tlen) 115 + chaps[len(chaps)-1].endSecs = uint32(tlen) 116 + } else { 117 + chaps[len(chaps)-1].endSecs = uint32(finalEnd) 118 + } 105 119 106 120 // ready to modify the file, clear out what's there 107 121 mp3.DeleteFrames("CTOC")