Пример #1
0
//This function is going to be the core of my scanner.
func (v *Mp4Video) Inspect(f io.ReadSeeker) (item *core.Item, err error) {
	item = &core.Item{
		Type: core.ItemTypeVideo,
	}

	//get the mvhd atom offset
	mvhd, err := getMp4MvhdAtom(f)
	if err != nil {
		return nil, fmt.Errorf("cannot find mvhd: %s", err)
	}

	//see if we can find the creation time
	created, err := getMp4CreationTimeFromMvhdAtom(f)
	if err != nil {
		return nil, fmt.Errorf("cannot get creation time: %s", err) //no creation, no dice
	}
	item.Created = core.AdjustTime(created)

	//return to mvhd to get duration
	f.Seek(mvhd, 0)
	duration, err := getMp4DurationFromMvhdAtom(f)
	if err == nil {
		v.Duration = duration
	}

	//getting size means finding the video track detail atom
	x, y, r, err := getMp4Dimensions(f)
	if err == nil {
		v.Width = int(x)
		v.Height = int(y)
		v.Orientation = r
	}

	latlon, err := getMp4Location(f)
	if err == nil {
		item.Location = latlon
	}

	//get size by seeking to end.
	v.Size, _ = f.Seek(0, 2)

	b, err := json.Marshal(v)
	if err != nil {
		return nil, fmt.Errorf("json marshal error: %s", err)
	}

	//set the metadata
	item.Meta = json.RawMessage(b)

	return
}
Пример #2
0
//This function is going to be the core of my scanner.
func (p *JpegPhoto) Inspect(f io.ReadSeeker) (item *core.Item, err error) {
	item = &core.Item{
		Type:     core.ItemTypePhoto,
		Location: &core.LatLon{},
	}
	p.Width = 0
	p.Height = 0
	p.Orientation = OrientedNormal
	p.Device = ""

	cfg, err := jpeg.DecodeConfig(f)
	if err != nil {
		return nil, err
	}
	p.Width = cfg.Width
	p.Height = cfg.Height

	f.Seek(0, 0) //rewind...
	//get date from exif
	exifInfo, err := exif.Decode(f)
	if err != nil {
		return nil, err //no exif, no photo
	}

	var createds []time.Time

	for _, field := range possibleExifDateTimeFields {
		tag, err := exifInfo.Get(field)
		if err != nil {
			//log.Println("no tag", field)
			continue
		}
		tag_val, err := tag.StringVal()
		if err != nil {
			log.Println("wrong type", field)
			continue
		}
		if tag_created, err := time.Parse(ExifDateFormat, tag_val); err == nil {
			if tag_created == exifDateBug {
				log.Println("EXIF DATE BUG:", field)
				continue
			}
			createds = append(createds, tag_created)
		}
	}
	if len(createds) == 0 || createds[0].IsZero() {
		return nil, fmt.Errorf("Could not get date photo taken")
	}

	item.Created = core.AdjustTime(createds[0])

	//now optional, orientation
	tag, err := exifInfo.Get(exif.Orientation)
	if err == nil {
		o, _ := tag.Int(0)
		p.Orientation = ExifOrientation(o)
		//swap height/width if needed.
		switch p.Orientation {
		case OrientedMirror270, OrientedNormal270, OrientedNormal90, OrientedMirror90:
			p.Width, p.Height = p.Height, p.Width
		}
	}

	//Device/Make
	tag, err = exifInfo.Get(exif.Make)
	if err == nil && tag.Format() == tiff.StringVal {
		p.Device, _ = tag.StringVal()
	}
	tag, err = exifInfo.Get(exif.Model)
	if err == nil && tag.Format() == tiff.StringVal {
		if p.Device == "" {
			p.Device, _ = tag.StringVal()
		} else {
			tag_val, _ := tag.StringVal()
			p.Device = p.Device + " " + tag_val
		}
	}

	//and GPS location
	setLocationFromExif(item.Location, exifInfo)

	//get size of file by seeking to the end.
	p.Size, _ = f.Seek(0, 2)

	b, err := json.Marshal(p)
	if err != nil {
		return nil, err
	}

	//now add meta to item.
	item.Meta = json.RawMessage(b)

	return
}
Пример #3
0
func main() {
	flag.Parse()
	if *version {
		fmt.Printf("OPFS %s\n", core.VERSION)
		return
	}
	if *usage {
		flag.Usage()
		return
	}
	if *dumpConfig {
		if err := core.WriteDefaultConfigTo(os.Stdout); err != nil {
			log.Fatal("Dump Config Error:", err)
		}
		os.Exit(0)
	}

	//make sure we use all available cores
	runtime.GOMAXPROCS(runtime.NumCPU())

	conf, err := os.Open(core.ExpandHome(*config))
	configuration := &core.Config{}
	if err != nil {
		if os.IsNotExist(err) && *config == defaultConfigLocation {
			//this ok, probably first run. write config file.
			if err = core.WriteDefaultConfig(core.ExpandHome(*config)); err != nil {
				log.Fatal("error creating default config file:", err)
			}
			configuration = core.DefaultConfig
		} else {
			log.Fatal("Error opening config file:", err)
		}
	} else {
		if err = json.NewDecoder(conf).Decode(configuration); err != nil {
			log.Fatal("Error reading Config File:", err)
		}
		conf.Close()
	}

	//now instatiate from config.
	service, err := core.NewService(configuration)
	if err != nil {
		log.Fatal("Error initialising service:", err)
	}

	if *importDir != "" {
		//single import job
		//work out tags

		var tags []string
		if *importTags != "" {
			tags = strings.Split(*importTags, ",")
		}

		log.Println(core.AllMimeTypes())

		opts := &core.ImportOptions{
			Dir:               *importDir,
			Tags:              tags,
			Time:              core.AdjustTime(time.Now()),
			MimeTypes:         core.AllMimeTypes(),
			DeleteAfterImport: *importDeleteAfter,
		}

		errors := service.Import(opts)
		for err := range errors {
			log.Println("ImportError:", err)
		}
		return
	}

	if *storeReindex {
		errors := service.ReindexFromStore()
		for err := range errors {
			log.Println("ImportError:", err)
		}
		return
	}

	if *daemon {
		log.Printf("OPFS: Starting API on  http://%s/\n", configuration.Api.Listen)
		var wg sync.WaitGroup
		wg.Add(1)
		errs, fini := service.WatchImport(&core.ImportOptions{
			MimeTypes:         core.AllMimeTypes(),
			DeleteAfterImport: true, //DANGER DANGER!
		})
		go func() {
			log.Println("API Fail:", service.ApiListen())
			wg.Done()
		}()
		go func() {
			for {
				select {
				case err := <-errs:
					log.Println("Import Watch Error:", err)
				case <-fini:
					break
				}
			}
		}()
		wg.Wait()
		//now shutdown
		close(fini)
		os.Exit(0)
	}

	//no option given...
	flag.Usage()
}