Metadata: Improve camera type detection based on make and model #4581

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2024-10-17 23:27:57 +02:00
parent 355b3d352c
commit bacdde7be7
10 changed files with 607 additions and 141 deletions

View file

@ -138,6 +138,7 @@ export class Photo extends RestModel {
CameraID: 0,
CameraMake: "",
CameraModel: "",
CameraType: "",
CameraSerial: "",
CameraSrc: "",
Lens: {},

View file

@ -38,8 +38,8 @@ func (Camera) TableName() string {
var UnknownCamera = Camera{
CameraSlug: UnknownID,
CameraName: "Unknown",
CameraMake: "",
CameraModel: "Unknown",
CameraMake: MakeNone,
CameraModel: ModelUnknown,
}
// CreateUnknownCamera initializes the database with an unknown camera if not exists
@ -50,8 +50,7 @@ func CreateUnknownCamera() {
// NewCamera creates a new camera entity from make and model names.
func NewCamera(makeName string, modelName string) *Camera {
makeName = strings.TrimSpace(makeName)
modelName = strings.TrimSpace(modelName)
cameraType := CameraTypes[strings.TrimSpace(modelName)]
modelName = strings.Trim(modelName, " \t\r\n-_")
if modelName == "" && makeName == "" {
return &UnknownCamera
@ -73,6 +72,9 @@ func NewCamera(makeName string, modelName string) *Camera {
modelName = strings.TrimSpace(modelName[len(makeName):])
}
// Determine device type based on make and model.
cameraType := GetCameraType(makeName, modelName)
var name []string
if makeName != "" {
@ -90,7 +92,7 @@ func NewCamera(makeName string, modelName string) *Camera {
CameraName: txt.Clip(cameraName, txt.ClipName),
CameraMake: txt.Clip(makeName, txt.ClipName),
CameraModel: txt.Clip(modelName, txt.ClipName),
CameraType: txt.Clip(cameraType, txt.ClipType),
CameraType: cameraType,
}
return result
@ -154,15 +156,28 @@ func (m *Camera) String() string {
// Scanner checks whether the model appears to be a scanner.
func (m *Camera) Scanner() bool {
if m.CameraType == CameraScanner {
switch m.CameraType {
case CameraTypeFilm, CameraTypeScanner:
return true
} else if m.CameraSlug == "" {
}
if m.CameraSlug == "" {
return false
}
return strings.Contains(m.CameraSlug, "scan")
}
// Mobile checks whether the model appears to be a mobile device.
func (m *Camera) Mobile() bool {
switch m.CameraType {
case CameraTypePhone, CameraTypeTablet:
return true
default:
return false
}
}
// Unknown returns true if the camera is not a known make or model.
func (m *Camera) Unknown() bool {
return m.CameraSlug == "" || m.CameraSlug == UnknownCamera.CameraSlug

View file

@ -1,70 +1,109 @@
package entity
const (
MakeNone = ""
MakeAcer = "Acer"
MakeApple = "Apple"
MakeAsus = "ASUS"
MakeCanon = "Canon"
MakeNikon = "NIKON"
MakeGoogle = "Google"
MakeMotorola = "Motorola"
MakeLG = "LG"
MakeHTC = "HTC"
MakeGoPro = "GoPro"
MakeCasio = "CASIO"
MakeKodak = "KODAK"
MakeLeica = "Leica"
MakeOlympus = "Olympus"
MakeMinolta = "Minolta"
MakeKonicaMinolta = "Konica Minolta"
MakePentax = "PENTAX"
MakeSamsung = "Samsung"
MakeSony = "SONY"
MakeSharp = "SHARP"
MakeHuawei = "HUAWEI"
MakeXiaomi = "Xiaomi"
MakeFuji = "FUJIFILM"
MakeBlackBerry = "BlackBerry"
MakeRaspberryPi = "Raspberry Pi"
MakePolaroid = "Polaroid"
MakeHasselblad = "Hasselblad"
MakeSigma = "SIGMA"
MakeOnePlus = "OnePlus"
MakeHewlettPackard = "HP"
MakeGarmin = "Garmin"
MakeRicoh = "RICOH"
MakeReolink = "Reolink"
MakeVenTrade = "VenTrade"
)
// CameraMakes maps internal make identifiers to normalized names.
var CameraMakes = map[string]string{
"acer": "Acer",
"ACER": "Acer",
"asus": "ASUS",
"Asus": "ASUS",
"ASUS_AI2302": "ASUS",
"apple": "Apple",
"Casio": "CASIO",
"CASIO COMPUTER": "CASIO",
"CASIO COMPUTER CO": "CASIO",
"CASIO COMPUTER CO.": "CASIO",
"CASIO COMPUTER CO.,LTD": "CASIO",
"CASIO COMPUTER CO.,LTD.": "CASIO",
"CASIO CORPORATION": "CASIO",
"Fujifilm": "FUJIFILM",
"FUJIFILM CORPORATION": "FUJIFILM",
"Garmin-Asus": "Garmin",
"google": "Google",
"GOOGLE": "Google",
"U63667E4U111368": "Google",
"Hewlett-Packard": "HP",
"htc": "HTC",
"Kodak": "KODAK",
"EASTMAN KODAK": "KODAK",
"EASTMAN KODAK COMPANY": "KODAK",
"GCMC": "KODAK",
"Leica Camera AG": "Leica",
"LEICA": "Leica",
"LG Electronics": "LG",
"LGE": "LG",
"lge": "LG",
"Minolta Co., Ltd.": "Minolta",
"MINOLTA CO.,LTD": "Minolta",
"KONICA MINOLTA": "Konica Minolta",
"Motorol": "Motorola",
"Motorola Mobility": "Motorola",
"motorola": "Motorola",
"samsung": "Samsung",
"SAMSUNG": "Samsung",
"Samsung Electronics": "Samsung",
"SAMSUNG TECHWIN Co.": "Samsung",
"SAMSUNG TECHWIN": "Samsung",
"Samsung Techwin": "Samsung",
"sharp": "SHARP",
"Sharp": "SHARP",
"sigma": "SIGMA",
"Sigma": "SIGMA",
"OLYMPUS": "Olympus",
"OLYMPUS CORPORATION": "Olympus",
"OLYMPUS DIGITAL CAMERA": "Olympus",
"OLYMPUS IMAGING CORP.": "Olympus",
"OLYMPUS OPTICAL CO.,LTD": "Olympus",
"ONEPLUS": "OnePlus",
"Nikon": "NIKON",
"NIKON CORPORATION": "NIKON",
"Huawei": "HUAWEI",
"RaspberryPi": "Raspberry Pi",
"RICOH IMAGING COMPANY, LTD.": "RICOH",
"Ricoh": "RICOH",
"Pentax": "PENTAX",
"PENTAX Corporation": "PENTAX",
"PENTAX CORPORATION": "PENTAX",
"Blackberry": "BlackBerry",
"Research In Motion": "BlackBerry",
"Sony": "SONY",
"VenTrade GmbH, Germany": "VenTrade",
"acer": MakeAcer,
"ACER": MakeAcer,
"asus": MakeAsus,
"Asus": MakeAsus,
"ASUS_AI2302": MakeAsus,
"apple": MakeApple,
"Casio": MakeCasio,
"CASIO COMPUTER": MakeCasio,
"CASIO COMPUTER CO": MakeCasio,
"CASIO COMPUTER CO.": MakeCasio,
"CASIO COMPUTER CO.,LTD": MakeCasio,
"CASIO COMPUTER CO.,LTD.": MakeCasio,
"CASIO CORPORATION": MakeCasio,
"Fujifilm": MakeFuji,
"FUJIFILM CORPORATION": MakeFuji,
"Garmin-Asus": MakeGarmin,
"google": MakeGoogle,
"GOOGLE": MakeGoogle,
"U63667E4U111368": MakeGoogle,
"Hewlett-Packard": MakeHewlettPackard,
"htc": MakeHTC,
"Kodak": MakeKodak,
"EASTMAN KODAK": MakeKodak,
"EASTMAN KODAK COMPANY": MakeKodak,
"GCMC": MakeKodak,
"Leica Camera AG": MakeLeica,
"LEICA": MakeLeica,
"LG Electronics": MakeLG,
"LGE": MakeLG,
"lge": MakeLG,
"Minolta Co., Ltd.": MakeMinolta,
"MINOLTA CO.,LTD": MakeMinolta,
"KONICA MINOLTA": MakeKonicaMinolta,
"Motorol": MakeMotorola,
"Motorola Mobility": MakeMotorola,
"motorola": MakeMotorola,
"samsung": MakeSamsung,
"SAMSUNG": MakeSamsung,
"Samsung Electronics": MakeSamsung,
"SAMSUNG TECHWIN Co.": MakeSamsung,
"SAMSUNG TECHWIN": MakeSamsung,
"Samsung Techwin": MakeSamsung,
"sharp": MakeSharp,
"Sharp": MakeSharp,
"sigma": MakeSigma,
"Sigma": MakeSigma,
"OLYMPUS": MakeOlympus,
"OLYMPUS CORPORATION": MakeOlympus,
"OLYMPUS DIGITAL CAMERA": MakeOlympus,
"OLYMPUS IMAGING CORP.": MakeOlympus,
"OLYMPUS OPTICAL CO.,LTD": MakeOlympus,
"ONEPLUS": MakeOnePlus,
"Nikon": MakeNikon,
"NIKON CORPORATION": MakeNikon,
"Huawei": MakeHuawei,
"XIAOMI": MakeXiaomi,
"RaspberryPi": MakeRaspberryPi,
"RICOH IMAGING COMPANY, LTD.": MakeRicoh,
"Ricoh": MakeRicoh,
"Pentax": MakePentax,
"PENTAX Corporation": MakePentax,
"PENTAX CORPORATION": MakePentax,
"Blackberry": MakeBlackBerry,
"Research In Motion": MakeBlackBerry,
"Sony": MakeSony,
"VenTrade GmbH, Germany": MakeVenTrade,
}

View file

@ -1,9 +1,25 @@
package entity
const (
ModelNone = ""
ModelUnknown = "Unknown"
ModelSlideNScan = "Slide N Scan"
ModelPhotoScan = "PhotoScan"
ModelCanoScan = "CanoScan"
ModelOpticFilm = "OpticFilm"
ModelScanSnap = "ScanSnap"
ModelMSScanner = "MS Scanner"
ModelIPhone = "iPhone"
ModelIPhoneSE = "iPhone SE"
ModelIPad = "iPad"
ModelIPadAir = "iPad Air"
ModelIPadPro = "iPad Pro"
)
// CameraModels maps internal model identifiers to normalized names.
var CameraModels = map[string]string{
// Mobile Devices:
"Z00AD": "ZenFone 2",
"Z00AD": "Zenfone 2",
"AI2302": "Zenfone 10",
"_AI2302": "Zenfone 10",
"ASUS_AI2302": "Zenfone 10",
@ -15,26 +31,26 @@ var CameraModels = map[string]string{
"Blackberry Leap": "BlackBerry Leap",
"Blackberry Classic": "BlackBerry Classic",
"Blackberry Passport": "BlackBerry Passport",
"iPhone SE (1st generation)": "iPhone SE",
"iPhone SE (2nd generation)": "iPhone SE",
"iPhone SE (3rd generation)": "iPhone SE",
"iPhone SE (4th generation)": "iPhone SE",
"iPhone SE (5th generation)": "iPhone SE",
"iPad (1st generation)": "iPad",
"iPad (2nd generation)": "iPad",
"iPad (3rd generation)": "iPad",
"iPad (4th generation)": "iPad",
"iPad (5th generation)": "iPad",
"iPad Air (1st generation)": "iPad Air",
"iPad Air (2nd generation)": "iPad Air",
"iPad Air (3rd generation)": "iPad Air",
"iPad Air (4th generation)": "iPad Air",
"iPad Air (5th generation)": "iPad Air",
"iPad Pro (1st generation)": "iPad Pro",
"iPad Pro (2nd generation)": "iPad Pro",
"iPad Pro (3rd generation)": "iPad Pro",
"iPad Pro (4th generation)": "iPad Pro",
"iPad Pro (5th generation)": "iPad Pro",
"iPhone SE (1st generation)": ModelIPhoneSE,
"iPhone SE (2nd generation)": ModelIPhoneSE,
"iPhone SE (3rd generation)": ModelIPhoneSE,
"iPhone SE (4th generation)": ModelIPhoneSE,
"iPhone SE (5th generation)": ModelIPhoneSE,
"iPad (1st generation)": ModelIPad,
"iPad (2nd generation)": ModelIPad,
"iPad (3rd generation)": ModelIPad,
"iPad (4th generation)": ModelIPad,
"iPad (5th generation)": ModelIPad,
"iPad Air (1st generation)": ModelIPadAir,
"iPad Air (2nd generation)": ModelIPadAir,
"iPad Air (3rd generation)": ModelIPadAir,
"iPad Air (4th generation)": ModelIPadAir,
"iPad Air (5th generation)": ModelIPadAir,
"iPad Pro (1st generation)": ModelIPadPro,
"iPad Pro (2nd generation)": ModelIPadPro,
"iPad Pro (3rd generation)": ModelIPadPro,
"iPad Pro (4th generation)": ModelIPadPro,
"iPad Pro (5th generation)": ModelIPadPro,
"GT-I9300": "Galaxy S3",
"SPH-L720": "Galaxy S4",
"SM-G920T": "Galaxy S6",
@ -210,12 +226,12 @@ var CameraModels = map[string]string{
"ILME-FX6V": "FX6 Cinema Line",
"ILME-FX6VK": "FX6 Cinema Line",
// Film Scanners:
"170 7472F20EEC14": "PhotoScan",
"RODFS40": "Slide N Scan",
"RODFS50": "Slide N Scan",
"RODFS60": "Slide N Scan",
"RODFS70": "Slide N Scan",
"RODFS80": "Slide N Scan",
"RODFS90": "Slide N Scan",
"SLIDE N SCAN": "Slide N Scan",
"170 7472F20EEC14": ModelPhotoScan,
"RODFS40": ModelSlideNScan,
"RODFS50": ModelSlideNScan,
"RODFS60": ModelSlideNScan,
"RODFS70": ModelSlideNScan,
"RODFS80": ModelSlideNScan,
"RODFS90": ModelSlideNScan,
"SLIDE N SCAN": ModelSlideNScan,
}

View file

@ -60,8 +60,9 @@ func TestNewCamera(t *testing.T) {
expected := &Camera{
CameraSlug: "canon-eos-6d",
CameraName: "Canon EOS 6D",
CameraMake: "Canon",
CameraMake: MakeCanon,
CameraModel: "EOS 6D",
CameraType: CameraTypeBody,
}
assert.Equal(t, expected, camera)
@ -84,7 +85,7 @@ func TestNewCamera(t *testing.T) {
expected := &Camera{
CameraSlug: "tg-4",
CameraName: "TG-4",
CameraMake: "",
CameraMake: MakeNone,
CameraModel: "TG-4",
}
@ -150,8 +151,101 @@ func TestCamera_Scanner(t *testing.T) {
})
t.Run("KODAKSlideNScan", func(t *testing.T) {
camera := NewCamera("GCMC", "RODFS50")
assert.Equal(t, MakeKodak+" "+ModelSlideNScan, camera.CameraName)
assert.Equal(t, CameraTypeFilm, camera.CameraType)
assert.Equal(t, MakeKodak, camera.CameraMake)
assert.Equal(t, ModelSlideNScan, camera.CameraModel)
assert.True(t, camera.Scanner())
assert.Equal(t, "KODAK", camera.CameraMake)
assert.Equal(t, "Slide N Scan", camera.CameraModel)
assert.False(t, camera.Mobile())
})
}
func TestCamera_Mobile(t *testing.T) {
t.Run("CanonEOSD30", func(t *testing.T) {
camera := NewCamera(MakeCanon, "EOS D30")
assert.Equal(t, CameraTypeBody, camera.CameraType)
assert.Equal(t, MakeCanon+" EOS D30", camera.CameraName)
assert.Equal(t, MakeCanon, camera.CameraMake)
assert.Equal(t, "EOS D30", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("CanonEOS6D", func(t *testing.T) {
camera := NewCamera(MakeCanon, "EOS 6D")
assert.Equal(t, CameraTypeBody, camera.CameraType)
assert.Equal(t, MakeCanon+" EOS 6D", camera.CameraName)
assert.Equal(t, MakeCanon, camera.CameraMake)
assert.Equal(t, "EOS 6D", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("CanonEOSR6", func(t *testing.T) {
camera := NewCamera(MakeCanon, "EOS R6")
assert.Equal(t, CameraTypeBody, camera.CameraType)
assert.Equal(t, MakeCanon+" EOS R6", camera.CameraName)
assert.Equal(t, MakeCanon, camera.CameraMake)
assert.Equal(t, "EOS R6", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("CanonCinema", func(t *testing.T) {
camera := NewCamera(MakeCanon, "EOS C100 Mark II")
assert.Equal(t, CameraTypeVideo, camera.CameraType)
assert.Equal(t, MakeCanon+" EOS C100 Mark II", camera.CameraName)
assert.Equal(t, MakeCanon, camera.CameraMake)
assert.Equal(t, "EOS C100 Mark II", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("iPhone", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPhone)
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeApple+" "+ModelIPhone, camera.CameraName)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPhone, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPad", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPad)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple+" "+ModelIPad, camera.CameraName)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPad, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPadAir", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPadAir)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPadAir, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPadPro", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPadPro)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPadPro, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("SamsungGalaxyS21", func(t *testing.T) {
camera := NewCamera(MakeSamsung, "Galaxy S21")
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeSamsung, camera.CameraMake)
assert.Equal(t, "Galaxy S21", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("SamsungGalaxyTab", func(t *testing.T) {
camera := NewCamera(MakeSamsung, "Galaxy Tab")
assert.Equal(t, MakeSamsung+" Galaxy Tab", camera.CameraName)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeSamsung, camera.CameraMake)
assert.Equal(t, "Galaxy Tab", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
}

View file

@ -1,46 +1,151 @@
package entity
import "strings"
type CameraType = string
const (
CameraUnknown CameraType = ""
CameraZLR CameraType = "zlr"
CameraSLR CameraType = "slr"
CameraDSLR CameraType = "dslr"
CameraMirrorless CameraType = "mirrorless"
CameraCCTV CameraType = "cctv"
CameraSpy CameraType = "spy"
CameraAction CameraType = "action"
CameraWebcam CameraType = "webcam"
CameraDashcam CameraType = "dashcam"
CameraAnalog CameraType = "analog"
CameraBridge CameraType = "bridge"
CameraCompact CameraType = "compact"
CameraInstant CameraType = "instant" // Polaroid
CameraStereo CameraType = "stereo" // 3D
CameraOmni CameraType = "omni" // 360 Degree
CameraPhone CameraType = "phone"
CameraTablet CameraType = "tablet"
CameraMobile CameraType = "mobile"
CameraScanner CameraType = "scanner"
CameraMovie CameraType = "movie"
CameraVideo CameraType = "video"
CameraSoftware CameraType = "software"
CameraOther CameraType = "other"
CameraTypeUnknown CameraType = "" // Default
CameraType3D CameraType = "3d" // Stereo 3D
CameraType360 CameraType = "360-degree" // 360 Degree
CameraTypeAction CameraType = "action" // GoPro
CameraTypeComputer CameraType = "computer" // Webcams
CameraTypeSurveillance CameraType = "surveillance" // Surveillance
CameraTypeBody CameraType = "body" // SLR, DSLR, Mirrorless, Medium Format
CameraTypeCompact CameraType = "compact" // Compact Cameras
CameraTypeInstant CameraType = "instant" // Polaroid
CameraTypePhone CameraType = "phone" // Mobile Phones
CameraTypeTablet CameraType = "tablet" // Tablets
CameraTypeFilm CameraType = "film" // Scanned Films
CameraTypeScanner CameraType = "scanner" // Other Scanners
CameraTypeVideo CameraType = "video" // Video Cameras
)
// CameraTypes maps internal model identifiers to camera types.
var CameraTypes = map[string]CameraType{
"Scan": CameraScanner,
"Scanner": CameraScanner,
"MS Scanner": CameraScanner,
"PhotoScan": CameraScanner,
"170 7472F20EEC14": CameraScanner,
"Slide N Scan": CameraScanner,
"RODFS40": CameraScanner,
"RODFS50": CameraScanner,
"RODFS60": CameraScanner,
"RODFS70": CameraScanner,
"RODFS80": CameraScanner,
"RODFS90": CameraScanner,
"360 CAM": CameraType360,
"Mi Sphere": CameraType360,
"Scan": CameraTypeScanner,
"Scanner": CameraTypeScanner,
ModelMSScanner: CameraTypeScanner,
ModelPhotoScan: CameraTypeScanner,
"170 7472F20EEC14": CameraTypeScanner,
ModelCanoScan: CameraTypeScanner,
ModelScanSnap: CameraTypeScanner,
ModelOpticFilm: CameraTypeScanner,
ModelSlideNScan: CameraTypeFilm,
"RODFS40": CameraTypeFilm,
"RODFS50": CameraTypeFilm,
"RODFS60": CameraTypeFilm,
"RODFS70": CameraTypeFilm,
"RODFS80": CameraTypeFilm,
"RODFS90": CameraTypeFilm,
}
// GetCameraType determines the camera type based on the make and model name.
func GetCameraType(makeName string, modelName string) CameraType {
// Detect the device type based on the exact model name.
if result, found := CameraTypes[modelName]; found {
return result
}
// Detect the device type for common brands.
switch makeName {
case MakeMotorola, MakeHTC, MakeLG, MakeOnePlus, MakeGarmin:
return CameraTypePhone
case MakeMinolta, MakeKonicaMinolta, MakePentax, MakeHasselblad, MakeSigma:
return CameraTypeBody
case MakeGoPro:
return CameraTypeAction
case MakeRaspberryPi:
return CameraTypeComputer
case MakePolaroid:
return CameraTypeInstant
case MakeRicoh:
return CameraTypeCompact
case MakeReolink, MakeVenTrade:
return CameraTypeSurveillance
case MakeApple:
if strings.HasPrefix(modelName, ModelIPhone) {
return CameraTypePhone
} else if strings.HasPrefix(modelName, ModelIPad) {
return CameraTypeTablet
}
case MakeGoogle:
if strings.HasPrefix(modelName, "Pixel ") {
if n := strings.ToLower(modelName); strings.Contains(n, "tab") || strings.Contains(n, "slate") {
return CameraTypeTablet
} else {
return CameraTypePhone
}
}
case MakeCanon:
if strings.HasPrefix(modelName, "Lide") {
return CameraTypeScanner
} else if strings.HasPrefix(modelName, "EOS ") {
if strings.HasPrefix(modelName, "EOS C") {
return CameraTypeVideo
}
return CameraTypeBody
} else if strings.HasPrefix(modelName, "Power") {
return CameraTypeCompact
}
case MakeSony:
if strings.HasPrefix(modelName, "Alpha") {
return CameraTypeBody
} else if strings.HasPrefix(modelName, "Xperia") {
return CameraTypePhone
} else {
return CameraTypeCompact
}
case MakeHuawei:
if n := strings.ToLower(modelName); strings.Contains(n, "tab") {
return CameraTypeTablet
} else if strings.HasPrefix(modelName, "P") ||
strings.HasPrefix(modelName, "Mate ") ||
strings.HasPrefix(modelName, "Honor ") {
return CameraTypePhone
}
case MakeXiaomi:
if n := strings.ToLower(modelName); strings.Contains(n, "tab") || strings.Contains(n, "pad") {
return CameraTypeTablet
} else {
return CameraTypePhone
}
case MakeSamsung:
if strings.HasPrefix(modelName, "Galaxy Tab") {
return CameraTypeTablet
} else if strings.HasPrefix(modelName, "Galaxy ") {
return CameraTypePhone
}
case MakeHewlettPackard:
if n := strings.ToLower(modelName); strings.Contains(n, "scan") ||
strings.Contains(n, "laser") ||
strings.Contains(n, "office") {
return CameraTypeScanner
}
}
// Try to recognize the device type by brand name.
if n := strings.ToLower(makeName); n != "" {
if strings.Contains(n, "scan") {
return CameraTypeScanner
}
}
// Try to recognize the device type by model name.
if n := strings.ToLower(modelName); n != "" {
if strings.Contains(n, "scan") {
return CameraTypeScanner
} else if strings.Contains(n, "pad") || strings.Contains(n, "tab") {
return CameraTypeTablet
} else if strings.Contains(n, "phone") || strings.Contains(n, "fone") || strings.Contains(n, "blackberry") {
return CameraTypePhone
} else if strings.Contains(n, "360") {
return CameraType360
}
}
return CameraTypeUnknown
}

View file

@ -0,0 +1,186 @@
package entity
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCamera_CameraType(t *testing.T) {
t.Run("Unknown", func(t *testing.T) {
camera := NewCamera("", "")
assert.Equal(t, CameraTypeUnknown, camera.CameraType)
assert.Equal(t, ModelUnknown, camera.CameraName)
assert.Equal(t, MakeNone, camera.CameraMake)
assert.Equal(t, ModelUnknown, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("Foo", func(t *testing.T) {
camera := NewCamera("foo", "")
assert.Equal(t, CameraTypeUnknown, camera.CameraType)
assert.Equal(t, "foo", camera.CameraMake)
assert.Equal(t, ModelNone, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("CanonEOS6D", func(t *testing.T) {
camera := NewCamera(MakeCanon, "EOS 6D")
assert.Equal(t, CameraTypeBody, camera.CameraType)
assert.Equal(t, MakeCanon+" EOS 6D", camera.CameraName)
assert.Equal(t, MakeCanon, camera.CameraMake)
assert.Equal(t, "EOS 6D", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("Hasselblad", func(t *testing.T) {
camera := NewCamera(MakeHasselblad, "L2D-20c")
assert.Equal(t, CameraTypeBody, camera.CameraType)
assert.Equal(t, MakeHasselblad, camera.CameraMake)
assert.Equal(t, "L2D-20c", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("iPhone", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPhone)
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeApple+" "+ModelIPhone, camera.CameraName)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPhone, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPad", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPad)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple+" "+ModelIPad, camera.CameraName)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPad, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPadAir", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPadAir)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPadAir, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("iPadPro", func(t *testing.T) {
camera := NewCamera(MakeApple, ModelIPadPro)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeApple, camera.CameraMake)
assert.Equal(t, ModelIPadPro, camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("GooglePixelTablet", func(t *testing.T) {
camera := NewCamera(MakeGoogle, "Pixel Tablet")
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeGoogle, camera.CameraMake)
assert.Equal(t, "Pixel Tablet", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("GooglePixelSlate", func(t *testing.T) {
camera := NewCamera(MakeGoogle, "Pixel Slate")
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeGoogle, camera.CameraMake)
assert.Equal(t, "Pixel Slate", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("GooglePixel8a", func(t *testing.T) {
camera := NewCamera(MakeGoogle, "Pixel 8a")
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeGoogle, camera.CameraMake)
assert.Equal(t, "Pixel 8a", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("HuaweiP30", func(t *testing.T) {
camera := NewCamera(MakeHuawei, "P30")
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeHuawei, camera.CameraMake)
assert.Equal(t, "P30", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("HuaweiMate20lite", func(t *testing.T) {
camera := NewCamera(MakeHuawei, "INE-LX2")
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeHuawei, camera.CameraMake)
assert.Equal(t, "Mate 20 lite", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("HuaweiMatePadPro", func(t *testing.T) {
camera := NewCamera(MakeHuawei, "MatePad Pro")
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeHuawei, camera.CameraMake)
assert.Equal(t, "MatePad Pro", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("XiaomiRedmiPad", func(t *testing.T) {
camera := NewCamera("XIAOMI", "Redmi Pad SE 8.7")
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeXiaomi, camera.CameraMake)
assert.Equal(t, "Redmi Pad SE 8.7", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("SamsungGalaxyS21", func(t *testing.T) {
camera := NewCamera(MakeSamsung, "Galaxy S21")
assert.Equal(t, CameraTypePhone, camera.CameraType)
assert.Equal(t, MakeSamsung, camera.CameraMake)
assert.Equal(t, "Galaxy S21", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("SamsungGalaxyTab", func(t *testing.T) {
camera := NewCamera(MakeSamsung, "Galaxy Tab")
assert.Equal(t, MakeSamsung+" Galaxy Tab", camera.CameraName)
assert.Equal(t, CameraTypeTablet, camera.CameraType)
assert.Equal(t, MakeSamsung, camera.CameraMake)
assert.Equal(t, "Galaxy Tab", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.True(t, camera.Mobile())
})
t.Run("PolaroidOne600Nero", func(t *testing.T) {
camera := NewCamera(MakePolaroid, "One600 Nero")
assert.Equal(t, MakePolaroid+" One600 Nero", camera.CameraName)
assert.Equal(t, CameraTypeInstant, camera.CameraType)
assert.Equal(t, MakePolaroid, camera.CameraMake)
assert.Equal(t, "One600 Nero", camera.CameraModel)
assert.False(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("MSScanner", func(t *testing.T) {
camera := NewCamera("", "MS Scanner")
assert.Equal(t, ModelMSScanner, camera.CameraName)
assert.Equal(t, ModelMSScanner, camera.CameraModel)
assert.Equal(t, MakeNone, camera.CameraMake)
assert.Equal(t, ModelMSScanner, camera.CameraModel)
assert.True(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("KODAKSlideNScan", func(t *testing.T) {
camera := NewCamera("GCMC", "RODFS50")
assert.Equal(t, MakeKodak+" "+ModelSlideNScan, camera.CameraName)
assert.Equal(t, CameraTypeFilm, camera.CameraType)
assert.Equal(t, MakeKodak, camera.CameraMake)
assert.Equal(t, ModelSlideNScan, camera.CameraModel)
assert.True(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
t.Run("HPLaserJetPro", func(t *testing.T) {
camera := NewCamera(MakeHewlettPackard, "LaserJet Pro")
assert.Equal(t, CameraTypeScanner, camera.CameraType)
assert.Equal(t, MakeHewlettPackard, camera.CameraMake)
assert.Equal(t, "LaserJet Pro", camera.CameraModel)
assert.True(t, camera.Scanner())
assert.False(t, camera.Mobile())
})
}

View file

@ -53,6 +53,7 @@ type Photo struct {
CameraSerial string `json:"CameraSerial,omitempty" select:"photos.camera_serial"`
CameraMake string `json:"CameraMake,omitempty" select:"cameras.camera_make"`
CameraModel string `json:"CameraModel,omitempty" select:"cameras.camera_model"`
CameraType string `json:"CameraType,omitempty" select:"cameras.camera_type"`
LensID uint `json:"LensID" select:"photos.lens_id"` // Lens
LensMake string `json:"LensMake,omitempty" select:"lenses.lens_model"`
LensModel string `json:"LensModel,omitempty" select:"lenses.lens_make"`

View file

@ -220,6 +220,7 @@ func TestPhotosResults_Merged(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -279,6 +280,7 @@ func TestPhotosResults_Merged(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -349,6 +351,7 @@ func TestPhotosResults_UIDs(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -408,6 +411,7 @@ func TestPhotosResults_UIDs(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -475,6 +479,7 @@ func TestPhotosResult_ShareFileName(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -538,6 +543,7 @@ func TestPhotosResult_ShareFileName(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -602,6 +608,7 @@ func TestPhotosResult_ShareFileName(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",

View file

@ -39,6 +39,7 @@ func TestPhotoResults_ViewerJSON(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",
@ -98,6 +99,7 @@ func TestPhotoResults_ViewerJSON(t *testing.T) {
CameraID: 0,
CameraModel: "",
CameraMake: "",
CameraType: "",
LensID: 0,
LensModel: "",
LensMake: "",