From 31ebc20ba78bf9bb890b3868ca7b0ca5914917fe Mon Sep 17 00:00:00 2001 From: Antonin Amand Date: Tue, 16 Sep 2014 00:06:37 +0200 Subject: [PATCH] Add IsVideo to types/camtypes FileInfo It is based on MIME type then falls back to extension. Change-Id: I71d80ec7cdcf94f4fa7feffa8186943abe0279ce --- pkg/types/camtypes/search.go | 52 +++++++++++++++++++++++++++++++ pkg/types/camtypes/search_test.go | 42 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 pkg/types/camtypes/search_test.go diff --git a/pkg/types/camtypes/search.go b/pkg/types/camtypes/search.go index 4b09976a8..d73b696b6 100644 --- a/pkg/types/camtypes/search.go +++ b/pkg/types/camtypes/search.go @@ -19,6 +19,7 @@ package camtypes import ( "bytes" "fmt" + "path/filepath" "strings" "time" @@ -111,6 +112,57 @@ func (fi *FileInfo) IsImage() bool { return strings.HasPrefix(fi.MIMEType, "image/") } +var videoExtensions = map[string]bool{ + "3gp": true, + "avi": true, + "flv": true, + "m1v": true, + "m2v": true, + "m4v": true, + "mkv": true, + "mov": true, + "mp4": true, + "mpeg": true, + "mpg": true, + "ogv": true, + "wmv": true, +} + +func (fi *FileInfo) IsVideo() bool { + if strings.HasPrefix(fi.MIMEType, "video/") { + return true + } + + var ext string + if e := filepath.Ext(fi.FileName); strings.HasPrefix(e, ".") { + ext = e[1:] + } else { + return false + } + + // Case-insensitive lookup. + // Optimistically assume a short ASCII extension and be + // allocation-free in that case. + var buf [10]byte + lower := buf[:0] + const utf8RuneSelf = 0x80 // from utf8 package, but not importing it. + for i := 0; i < len(ext); i++ { + c := ext[i] + if c >= utf8RuneSelf { + // Slow path. + return videoExtensions[strings.ToLower(ext)] + } + if 'A' <= c && c <= 'Z' { + lower = append(lower, c+('a'-'A')) + } else { + lower = append(lower, c) + } + } + // The conversion from []byte to string doesn't allocate in + // a map lookup. + return videoExtensions[string(lower)] +} + // ImageInfo describes an image file. // // The Width and Height are uint16s to save memory in index/corpus.go, and that's diff --git a/pkg/types/camtypes/search_test.go b/pkg/types/camtypes/search_test.go new file mode 100644 index 000000000..dd009570e --- /dev/null +++ b/pkg/types/camtypes/search_test.go @@ -0,0 +1,42 @@ +/* +Copyright 2014 The Camlistore Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package camtypes + +import "testing" + +var fileInfoVideoTable = []struct { + fi *FileInfo + video bool +}{ + {&FileInfo{FileName: "some.mp4", MIMEType: "application/octet-stream"}, true}, + {&FileInfo{FileName: "IMG_1231.MOV", MIMEType: "application/octet-stream"}, true}, + {&FileInfo{FileName: "movie.mkv", MIMEType: "application/octet-stream"}, true}, + {&FileInfo{FileName: "movie.məv", MIMEType: "application/octet-stream"}, false}, + {&FileInfo{FileName: "tape", MIMEType: "video/webm"}, true}, + {&FileInfo{FileName: "tape", MIMEType: "application/ogg"}, false}, + {&FileInfo{FileName: "IMG_12312.jpg", MIMEType: "application/octet-stream"}, false}, + {&FileInfo{FileName: "IMG_12312.jpg", MIMEType: "image/jpeg"}, false}, +} + +func TestIsVideo(t *testing.T) { + for _, example := range fileInfoVideoTable { + if example.fi.IsVideo() != example.video { + t.Errorf("IsVideo failed video=%t filename=%s mimetype=%s", + example.video, example.fi.FileName, example.fi.MIMEType) + } + } +}