Esempio n. 1
0
File: codec.go Progetto: shazow/mog
func (rf Reader) Metadata(ft tag.FileType) (*SongInfo, tag.Metadata, []byte, error) {
	r, sz, err := rf()
	if err != nil {
		return nil, nil, nil, err
	}
	if sz == 0 {
		return nil, nil, nil, fmt.Errorf("cannot get metadata with unknown size")
	}
	b, err := ioutil.ReadAll(r)
	r.Close()
	if err != nil {
		return nil, nil, nil, err
	}
	m, err := tag.ReadFrom(bytes.NewReader(b))
	if err != nil {
		return nil, nil, nil, err
	}
	if m.FileType() != ft {
		return nil, nil, nil, fmt.Errorf("expected filetype %v, got %v", ft, m.FileType())
	}
	track, _ := m.Track()
	si := &SongInfo{
		Artist:   m.Artist(),
		Title:    m.Title(),
		Album:    m.Album(),
		Track:    float64(track),
		ImageURL: dataURL(m),
	}
	return si, m, b, nil
}
Esempio n. 2
0
func processPath(path string) (*track, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	m, err := tag.ReadFrom(f)
	if err != nil {
		return nil, err
	}

	fileInfo, err := f.Stat()
	if err != nil {
		return nil, err
	}

	createdTime, err := getCreatedTime(path)
	if err != nil {
		return nil, err
	}

	return &track{
		Metadata:    m,
		Location:    path,
		FileInfo:    fileInfo,
		CreatedTime: createdTime,
	}, nil
}
// Get the metadatas of a file
func getMetadatas(f *os.File) tag.Metadata {
	m, err := tag.ReadFrom(f)

	if err != nil {
		log.Fatal(err)
	}

	return m
}
Esempio n. 4
0
func (c App) Update() r.Result {
	scanpath := "/media/storage/Music.Subsonic"

	go filepath.Walk(scanpath, func(path string, file os.FileInfo, err error) error {
		if file.IsDir() {
			return nil
		}

		name := file.Name()
		five := name[len(name)-5:]
		four := five[1:]
		valid_type := false

		switch four {
		case ".mp3", ".ogg":
			valid_type = true
		}

		switch five {
		case ".flac":
			valid_type = true
		}

		if !valid_type {
			return nil
		}

		song := models.Song{Path: path}

		Db.Where("path = ?", path).First(&song)

		f, _ := os.Open(path)   // XXX error checking required here
		m, _ := tag.ReadFrom(f) // XXX error checking required here
		parts := strings.Split(path[len(scanpath)+1:], "/")

		song.Title = m.Title()
		song.Artist = m.Artist()
		song.ArtistPath = parts[0]
		song.Album = m.Album()
		song.AlbumPath = parts[1]

		if Db.NewRecord(song) {
			Db.Create(&song)
		} else {
			Db.Save(&song)
		}

		song = models.Song{}

		return nil
	})

	return c.Render()
}
Esempio n. 5
0
// NewTrack attempts to read the meta data from a file into a Track
// data structure. The string "Unknown" will be used in place of a
// blank artist name and "Untitled" in place of blank album and track
// titles.
func NewTrack(path string) (*Track, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	m, err := tag.ReadFrom(f)
	if err != nil {
		return nil, err
	}

	artist := m.Artist()
	if artist == "" {
		artist = "Unknown"
	}

	title := m.Title()
	if title == "" {
		title = "Untitled"
	}

	album := m.Album()
	if album == "" {
		album = "Untitled"
	}

	fmt.Printf(" Adding: %s - %s\r", artist, title)

	trackNumber, trackTotal := m.Track()
	discNumber, discTotal := m.Disc()

	t := &Track{
		m.FileType(),
		title,
		album,
		artist,
		m.AlbumArtist(),
		m.Composer(),
		m.Genre(),
		m.Year(),
		trackNumber,
		trackTotal,
		discNumber,
		discTotal,
		m.Lyrics(),
		"",
	}

	return t, nil
}
Esempio n. 6
0
func main() {
	flag.Parse()

	if flag.NArg() != 1 {
		usage()
		return
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Printf("error loading file: %v", err)
		return
	}
	defer f.Close()

	m, err := tag.ReadFrom(f)
	if err != nil {
		fmt.Printf("error reading file: %v\n", err)
		return
	}

	printMetadata(m)

	if raw {
		fmt.Println()
		fmt.Println()

		tags := m.Raw()
		for k, v := range tags {
			if _, ok := v.(*tag.Picture); ok {
				fmt.Printf("%#v: %v\n", k, v)
				continue
			}
			fmt.Printf("%#v: %#v\n", k, v)
		}
	}

	if extractMBZ {
		b, err := json.MarshalIndent(mbz.Extract(m), "", "  ")
		if err != nil {
			fmt.Printf("error marshalling MusicBrainz info: %v\n", err)
			return
		}

		fmt.Printf("\nMusicBrainz Info:\n%v\n", string(b))
	}
}
Esempio n. 7
0
// AlbumArt takes a path to an audio file and returns the album
// artwork if found.
func AlbumArt(path string) (*tag.Picture, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	m, err := tag.ReadFrom(f)
	if err != nil {
		return nil, err
	}

	if m.Picture() == nil {
		return nil, errors.New("No artwork found.")
	}

	return m.Picture(), nil
}
Esempio n. 8
0
File: player.go Progetto: andynu/rfk
func logMetadata(path string) {
	f, err := os.Open(path)
	if err != nil {
		log.Printf("Could not load metadata: %q", err)
		return
	}
	defer f.Close()

	m, err := tag.ReadFrom(f)
	if err != nil {
		log.Printf("Could not load metadata: %q", err)
		return
	}

	log.Printf("\tTitle: %q", m.Title())
	log.Printf("\tAlbum: %q", m.Album())
	log.Printf("\tArtist: %q", m.Artist())
}
Esempio n. 9
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]++
			}
		}()
	}
}
Esempio n. 10
0
File: ident.go Progetto: andynu/rfk
// if something goes wrong, you get a blank one.
func metaData(path string) (SongMeta, error) {
	var meta SongMeta

	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		return meta, err
	}

	m, err := tag.ReadFrom(f)
	if err != nil {
		return meta, err
	}

	meta.Title = m.Title()
	meta.Album = m.Album()
	meta.Artist = m.Artist()

	return meta, nil
}
Esempio n. 11
0
// Open the given file and return an http.File which contains the artwork, and hence
// the Name() of the returned file will have an extention for the artwork, not the
// media file.
func (afs artworkFileSystem) Open(ctx context.Context, path string) (http.File, error) {
	f, err := afs.FileSystem.Open(ctx, path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		return nil, err
	}

	var m tag.Metadata
	m, err = tag.ReadFrom(f)
	if err != nil {
		return nil, fmt.Errorf("error extracting picture from '%v': %v", path, err)
	}

	p := m.Picture()
	if p == nil {
		return nil, fmt.Errorf("no picture attached to '%v'", path)
	}

	name := stat.Name()
	if p.Ext != "" {
		name += "." + p.Ext
	}

	return &file{
		ReadSeeker: bytes.NewReader(p.Data),
		stat: &fileInfo{
			name:    name,
			size:    int64(len(p.Data)),
			modTime: stat.ModTime(),
		},
	}, nil
}
Esempio n. 12
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
}
Esempio n. 13
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
}