Exemple #1
0
func audioFileChecksum(path string) (string, error) {
	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		return "", err
	}
	checksum, err := tag.Sum(f)
	if err != nil {
		return "", err
	}
	return checksum, nil
}
Exemple #2
0
func audioFileChecksum(path string) {
	sem <- true
	defer func() { <-sem }()
	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		out <- fmt.Sprintf("%q\t%q", err, path)
		return
	}
	checksum, err := tag.Sum(f)
	if err != nil {
		out <- fmt.Sprintf("%q\t%q", err, path)
		return
	}
	out <- fmt.Sprintf("%s\t%q", checksum, path)
}
Exemple #3
0
func (p *processor) do(ch <-chan string) {
	for path := range ch {
		func() {
			defer func() {
				if p := recover(); p != nil {
					fmt.Printf("Panicing at: %v", path)
					panic(p)
				}
			}()
			tf, err := os.Open(path)
			if err != nil {
				p.decodingErrors["error opening file"]++
				return
			}
			defer tf.Close()

			_, _, err = tag.Identify(tf)
			if err != nil {
				fmt.Println("IDENTIFY:", path, err.Error())
			}

			_, err = tag.ReadFrom(tf)
			if err != nil {
				fmt.Println("READFROM:", path, err.Error())
				p.decodingErrors[err.Error()]++
			}

			if sum {
				_, err = tf.Seek(0, os.SEEK_SET)
				if err != nil {
					fmt.Println("DIED:", path, "error seeking back to 0:", err)
					return
				}

				h, err := tag.Sum(tf)
				if err != nil {
					fmt.Println("SUM:", path, err.Error())
					p.hashErrors[err.Error()]++
				}
				p.hashes[h]++
			}
		}()
	}
}
Exemple #4
0
func main() {
	if len(os.Args) != 2 {
		fmt.Printf("usage: %v filename\n", os.Args[0])
		return
	}

	f, err := os.Open(os.Args[1])
	if err != nil {
		fmt.Printf("error loading file: %v", err)
		os.Exit(1)
	}
	defer f.Close()

	h, err := tag.Sum(f)
	if err != nil {
		fmt.Printf("error constructing checksum: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(h)
}
Exemple #5
0
func scanDb() (tracks []*googm.Track, uploadFiles []*os.File) {
	var count int
	if err := DB.QueryRow("select count(*) as total from files where modtime > IFNULL(googmtime,0)").Scan(&count); err != nil {
		switch {
		case err == sql.ErrNoRows:
			p.INFO.Println("No changes found: error: " + err.Error())
		default:
			p.ERROR.Println(err)
			return
		}
	}
	p.MSG.Println("Starting to load from Db:")
	progress := pb.StartNew(count)
	rows, err := DB.Query("select fullpath from files where modtime > IFNULL(googmtime,0)")
	if err != nil {
		p.ERROR.Println("select failed; " + err.Error())
		panic(err)
	}
	defer rows.Close()
	var fullpath string
	p.INFO.Printf("%-15v %-35v %-15v %-15v %2v/%-6v\n", "ClientId", "Title", "Album", "Artist", "##", "T#", "")
db_scan_loop:
	for rows.Next() {
		if !VERBOSE {
			progress.Increment()
		} // show a progress bar; else it shows per file details.
		err := rows.Scan(&fullpath)
		if err != nil {
			panic(err)
		}
		fh, err := os.Open(fullpath)
		checksum, err := tag.Sum(fh)
		if err = rewind(fh, err); err != nil {
			p.ERROR.Println("FAILED CHECKSUM READ: [file skipped] " + err.Error() + fullpath)
			C_INVALID++
			continue db_scan_loop
		}

		t, err := tag.ReadFrom(fh)
		if err = rewind(fh, err); err != nil {
			p.ERROR.Println("FAILED TAG READ: [file skipped] " + fullpath + " with error: " + err.Error())
			C_INVALID++
			continue db_scan_loop
		}
		track_num, track_total := t.Track()
		disc_num, disc_total := t.Disc()
		p.INFO.Printf("%-15v %-35v %-15v %-15v %-2v/%-6v", checksum, t.Title(), t.Album(), t.Artist(), track_num, track_total)
		track := &googm.Track{
			ClientId:        checksum,
			Title:           t.Title(),
			Album:           t.Album(),
			Artist:          t.Artist(),
			AlbumArtist:     t.AlbumArtist(),
			Composer:        t.Composer(),
			Year:            t.Year(),
			Genre:           t.Genre(),
			TrackNumber:     track_num,
			TotalTrackCount: track_total,
			DiscNumber:      disc_num,
			TotalDiscCount:  disc_total,
		}
		tracks = append(tracks, track)
		uploadFiles = append(uploadFiles, fh)
		C_TOTAL++
	}
	if err = rows.Err(); err != nil {
		panic(err)
	}
	return
}
Exemple #6
0
func scanDir(dir string) (tracks []*googm.Track, uploadFiles []*os.File) {
	// remove the trailing slash if present. I need uniformity.
	dir = strings.TrimRight(dir, "\\/")
	var err error
	p.INFO.Println("Scanning Directory: " + dir)
	folder, err := os.Open(dir)
	if err != nil {
		p.ERROR.Println("=====START-MESSAGE=====")
		p.ERROR.Println("Failed to Open [directory]: ]" + dir + "]")
		p.ERROR.Println("Error message: " + err.Error())
		p.ERROR.Println("Advice: Probably an invalid directory path used for music root location. See directory above listed between sqaure brackets. Ensure you are not escaping the trailing quote")
		p.ERROR.Println("=====END-MESSAGE=====")
		panic(err)
	}
	defer folder.Close()
	folderFiles, err := folder.Readdir(0)
	if err != nil {
		p.ERROR.Println("Error reading files in directory " + dir)
		p.ERROR.Println("Error message: " + err.Error())
		panic(err)
	}
	// EDH NOTE - not sure the SQL types to set googmid, googmtime, and sum to, may need to be varchar?
	_, err = DB.Exec(`CREATE TABLE IF NOT EXISTS ` + `files` + ` ( ` +
		`fullpath text not null primary key, ` +
		`directory text not null, ` +
		`filename text not null, ` +
		`extension text not null, ` +
		`filesize int not null, ` +
		`modtime int not null, ` +
		`googmid bigint, ` +
		`googmtime int, ` +
		`format text not null, ` +
		`filetype text not null, ` +
		`checksum bigint not null, ` +
		`title text, ` +
		`album text, ` +
		`artist text, ` +
		`album_artist text, ` +
		`composer text, ` +
		`genre text, ` +
		`year int, ` +
		`track_num int, ` +
		`track_total int, ` +
		`disc_num int, ` +
		`disc_total int, ` +
		`has_image bool not null, ` +
		`lyrics text` +
		`)`)
	if err != nil {
		p.ERROR.Println("The table creation failed with error:" + err.Error())
		panic(err)
	}
per_file_loop:
	for _, fileinfo := range folderFiles {
		C_TOTAL++
		p.TRACE.Println(fileinfo.Name() + " is dir=" + strconv.FormatBool(fileinfo.IsDir()) + " with size=" + strconv.FormatInt(fileinfo.Size(), 10) + " last modified on " + fileinfo.ModTime().String())
		fullpath := dir + "/" + fileinfo.Name()
		arr := strings.Split(fileinfo.Name(), ".")
		extension := arr[len(arr)-1]
		switch {
		case fileinfo.IsDir():
			C_DIRS++
			p.DEBUG.Println("file is in fact a directory; recursively scanning: " + fullpath)
			scanDir(fullpath)
			continue per_file_loop
		case !validateFile(fullpath):
			C_INVALID++
			p.WARN.Println("file is not valid music, skipping: " + fullpath)
			continue per_file_loop
		case !ForceUpdate && !shouldFileUpload(fullpath):
			C_SKIPPED++
			p.DEBUG.Println("File is unchanged since the last upload and will not be uploaded, unless overridden with -f")
			continue per_file_loop
		}
		C_UPDATED++
		// get a file handle (fh) for the upcoming tag read
		fh, err := os.Open(fullpath)
		if err != nil {
			p.ERROR.Println("FAILED OS READ: [file skipped] " + err.Error() + fullpath)
			C_INVALID++
			continue per_file_loop
		}
		//defer fh.Close()
		// get a checksum -- tag.Sum -- see tag/Sum.go func Sum() only does a checksum of media part of the file, that is the part after the tag, thus the checksum should stay constant despite changes to the tag of the file. The purpose for this is to create a STATIC UNIQUE IDENTIFIER for the file that is consistent across time.
		checksum, err := tag.Sum(fh)
		if err = rewind(fh, err); err != nil {
			p.ERROR.Println("FAILED CHECKSUM READ: [file skipped] " + err.Error() + fullpath)
			C_INVALID++
			continue per_file_loop
		}
		// read the id tags
		t, err := tag.ReadFrom(fh)
		if err = rewind(fh, err); err != nil {
			p.ERROR.Println("FAILED TAG READ: [file skipped] " + err.Error() + fullpath)
			C_INVALID++
			continue per_file_loop
		}

		var hasimage bool = false
		track_num, track_total := t.Track()
		disc_num, disc_total := t.Disc()
		if t.Picture() != nil {
			hasimage = true
		}
		track := &googm.Track{
			ClientId:        checksum,
			Title:           t.Title(),
			Album:           t.Album(),
			Artist:          t.Artist(),
			AlbumArtist:     t.AlbumArtist(),
			Composer:        t.Composer(),
			Year:            t.Year(),
			Genre:           t.Genre(),
			TrackNumber:     track_num,
			TotalTrackCount: track_total,
			DiscNumber:      disc_num,
			TotalDiscCount:  disc_total,
		}
		tracks = append(tracks, track)
		uploadFiles = append(uploadFiles, fh)
		stmt, err := DB.Prepare(`INSERT OR REPLACE INTO ` + `files` + `(` +
			`fullpath, ` +
			`directory, ` +
			`filename, ` +
			`extension, ` +
			`filesize, ` +
			`modtime, ` +
			`format, ` +
			`filetype, ` +
			`checksum, ` +
			`title, ` +
			`album, ` +
			`artist, ` +
			`album_artist, ` +
			`composer, ` +
			`genre, ` +
			`year, ` +
			`track_num, ` +
			`track_total, ` +
			`disc_num, ` +
			`disc_total, ` +
			`has_image, ` +
			`lyrics ` +
			`) VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? );`)
		if err != nil {
			p.ERROR.Println("Query failed - could not insert data for file: " + fileinfo.Name())
		}
		_, err = stmt.Exec(
			fullpath,
			dir,
			fileinfo.Name(),
			extension,
			fileinfo.Size(),
			fileinfo.ModTime().Unix(),
			string(t.Format()),
			string(t.FileType()),
			checksum,
			t.Title(),
			t.Album(),
			t.Artist(),
			t.AlbumArtist(),
			t.Composer(),
			t.Genre(),
			t.Year(),
			track_num,
			track_total,
			disc_num,
			disc_total,
			hasimage,
			t.Lyrics(),
		)
		if err != nil {
			panic(err)
		}
	}
	p.INFO.Println("ScanDir( )-->")
	p.INFO.Printf("Sending %v tracks", len(tracks))
	p.INFO.Printf("Sending %v files", len(uploadFiles))
	return
}