Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
e580a117d6
commit
ca154f3bb3
17 changed files with 238 additions and 172 deletions
|
@ -95,10 +95,10 @@
|
|||
:label="labels.year"
|
||||
flat solo hide-details
|
||||
color="secondary-dark"
|
||||
item-value="Year"
|
||||
item-text="Name"
|
||||
item-value="value"
|
||||
item-text="text"
|
||||
v-model="filter.year"
|
||||
:items="yearOptions">
|
||||
:items="yearOptions()">
|
||||
</v-select>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md3 pa-2 class="p-month-select">
|
||||
|
@ -106,8 +106,8 @@
|
|||
:label="labels.month"
|
||||
flat solo hide-details
|
||||
color="secondary-dark"
|
||||
item-value="Month"
|
||||
item-text="Name"
|
||||
item-value="value"
|
||||
item-text="text"
|
||||
v-model="filter.month"
|
||||
:items="monthOptions()">
|
||||
</v-select>
|
||||
|
@ -175,7 +175,8 @@
|
|||
lenses: [{ID: 0, Name: this.$gettext("All Lenses")}],
|
||||
colors: [{Slug: "", Name: this.$gettext("All Colors")}],
|
||||
categories: [{Slug: "", Name: this.$gettext("All Categories")}],
|
||||
months: [{Month: 0, Name: this.$gettext("All Months")}],
|
||||
months: [{value: 0, text: this.$gettext("All Months")}],
|
||||
years: [{value: 0, text: this.$gettext("All Years")}],
|
||||
},
|
||||
options: {
|
||||
'views': [
|
||||
|
@ -221,21 +222,6 @@
|
|||
categoryOptions() {
|
||||
return this.all.categories.concat(this.config.categories);
|
||||
},
|
||||
yearOptions() {
|
||||
let result = [
|
||||
{"Year": 0, "Name": this.$gettext("All Years")},
|
||||
];
|
||||
|
||||
if (this.config.years) {
|
||||
for (let i = 0; i < this.config.years.length; i++) {
|
||||
result.push({"Year": this.config.years[i], "Name": this.config.years[i].toString()});
|
||||
}
|
||||
}
|
||||
|
||||
result.push({"Year": -1, "Name": this.$gettext("Unknown")});
|
||||
|
||||
return result;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
colorOptions() {
|
||||
|
@ -244,6 +230,9 @@
|
|||
monthOptions() {
|
||||
return this.all.months.concat(options.Months());
|
||||
},
|
||||
yearOptions() {
|
||||
return this.all.years.concat(options.IndexedYears());
|
||||
},
|
||||
dropdownChange() {
|
||||
this.filterChange();
|
||||
|
||||
|
|
|
@ -48,61 +48,70 @@
|
|||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md3 pa-2 class="p-date-select">
|
||||
<v-flex xs12 sm6 md2 pa-2>
|
||||
<v-autocomplete
|
||||
@change="updateTime"
|
||||
:disabled="disabled"
|
||||
:label="$gettext('Day')"
|
||||
hide-details
|
||||
color="secondary-dark"
|
||||
v-model="model.Day"
|
||||
:items="options.Days()"
|
||||
class="input-day">
|
||||
</v-autocomplete>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md2 pa-2>
|
||||
<v-autocomplete
|
||||
@change="updateTime"
|
||||
:disabled="disabled"
|
||||
:label="$gettext('Month')"
|
||||
hide-details
|
||||
color="secondary-dark"
|
||||
v-model="model.Month"
|
||||
:items="options.Months()"
|
||||
class="input-month">
|
||||
</v-autocomplete>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md2 pa-2>
|
||||
<v-autocomplete
|
||||
@change="updateTime"
|
||||
:disabled="disabled"
|
||||
:label="$gettext('Year')"
|
||||
hide-details
|
||||
color="secondary-dark"
|
||||
v-model="model.Year"
|
||||
:items="options.Years()"
|
||||
class="input-year">
|
||||
</v-autocomplete>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md2 class="pa-2">
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
:value="timeLocalFormatted"
|
||||
:value="localTime"
|
||||
browser-autocomplete="off"
|
||||
:label="labels.localtime"
|
||||
:label="$gettext('Local Time')"
|
||||
readonly
|
||||
hide-details
|
||||
color="secondary-dark"
|
||||
class="input-local-time"
|
||||
></v-text-field>
|
||||
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md3 pa-2 class="p-date-select">
|
||||
|
||||
<v-flex xs12 sm6 md2 pa-2>
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
@change="updateTime"
|
||||
v-model="time"
|
||||
:label="labels.utctime"
|
||||
:label="$gettext('Time UTC')"
|
||||
hide-details return-masked-value
|
||||
mask="##:##:##"
|
||||
color="secondary-dark"
|
||||
class="input-utc-time"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6 md3 class="pa-2 p-date-select">
|
||||
<v-menu
|
||||
:disabled="disabled"
|
||||
:close-on-content-click="false"
|
||||
full-width
|
||||
max-width="290"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
:value="dateFormatted"
|
||||
browser-autocomplete="off"
|
||||
:label="labels.utcdate"
|
||||
readonly
|
||||
hide-details
|
||||
v-on="on"
|
||||
color="secondary-dark"
|
||||
class="input-utc-date"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
color="secondary-dark"
|
||||
v-model="date"
|
||||
@change="showDatePicker = false"
|
||||
></v-date-picker>
|
||||
</v-menu>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md3 class="pa-2 p-timezone-select">
|
||||
<v-flex xs12 sm6 md2 class="pa-2">
|
||||
<v-autocomplete
|
||||
@change="updateTime"
|
||||
:disabled="disabled"
|
||||
|
@ -117,6 +126,34 @@
|
|||
</v-autocomplete>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md4 class="pa-2">
|
||||
<v-autocomplete
|
||||
:disabled="disabled"
|
||||
:label="labels.country"
|
||||
hide-details
|
||||
browser-autocomplete="off"
|
||||
color="secondary-dark"
|
||||
item-value="Code"
|
||||
item-text="Name"
|
||||
v-model="model.Country"
|
||||
:items="countries"
|
||||
class="input-country">
|
||||
</v-autocomplete>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md2 class="pa-2">
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
hide-details
|
||||
browser-autocomplete="off"
|
||||
:label="labels.altitude"
|
||||
placeholder=""
|
||||
color="secondary-dark"
|
||||
v-model="model.Altitude"
|
||||
class="input-altitude"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md3 class="pa-2">
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
|
@ -143,34 +180,6 @@
|
|||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md3 class="pa-2">
|
||||
<v-text-field
|
||||
:disabled="disabled"
|
||||
hide-details
|
||||
browser-autocomplete="off"
|
||||
:label="labels.altitude"
|
||||
placeholder=""
|
||||
color="secondary-dark"
|
||||
v-model="model.Altitude"
|
||||
class="input-altitude"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 sm6 md3 class="pa-2 p-countries-select">
|
||||
<v-autocomplete
|
||||
:disabled="disabled"
|
||||
:label="labels.country"
|
||||
hide-details
|
||||
browser-autocomplete="off"
|
||||
color="secondary-dark"
|
||||
item-value="Code"
|
||||
item-text="Name"
|
||||
v-model="model.Country"
|
||||
:items="countries"
|
||||
class="input-country">
|
||||
</v-autocomplete>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 md6 pa-2 class="p-camera-select">
|
||||
<v-select
|
||||
:disabled="disabled"
|
||||
|
@ -420,9 +429,6 @@
|
|||
language: this.$gettext("Language"),
|
||||
timezone: this.$gettext("Time Zone"),
|
||||
title: this.$gettext("Title"),
|
||||
localtime: this.$gettext("Local Time"),
|
||||
utctime: this.$gettext("UTC Time"),
|
||||
utcdate: this.$gettext("UTC Date"),
|
||||
latitude: this.$gettext("Latitude"),
|
||||
longitude: this.$gettext("Longitude"),
|
||||
altitude: this.$gettext("Altitude (m)"),
|
||||
|
@ -439,23 +445,18 @@
|
|||
},
|
||||
showDatePicker: false,
|
||||
showTimePicker: false,
|
||||
date: "",
|
||||
time: "",
|
||||
dateFormatted: "",
|
||||
timeFormatted: "",
|
||||
timeLocalFormatted: "",
|
||||
localTime: "",
|
||||
textRule: v => v.length <= this.$config.get('clip') || this.$gettext("Text too long"),
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
date() {
|
||||
if (!this.date) {
|
||||
this.dateFormatted = "";
|
||||
this.timeLocalFormatted = "";
|
||||
return
|
||||
model() {
|
||||
if (!this.model.hasId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dateFormatted = DateTime.fromISO(this.date).toLocaleString(DateTime.DATE_FULL);
|
||||
this.updateTime();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
@ -468,29 +469,22 @@
|
|||
},
|
||||
methods: {
|
||||
updateTime() {
|
||||
if (!this.time) {
|
||||
this.time = DateTime.fromISO(this.model.TakenAt).toUTC().toFormat("HH:mm:ss");
|
||||
return;
|
||||
const isoDate = this.model.isoDate(this.time);
|
||||
|
||||
if(!isoDate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.date) {
|
||||
return;
|
||||
}
|
||||
this.model.TakenAt = isoDate;
|
||||
|
||||
this.timeFormatted = DateTime.fromISO(this.time).toLocaleString(DateTime.TIME_24_WITH_SECONDS);
|
||||
const utcDate = this.model.utcDate();
|
||||
|
||||
const utcDate = this.date + "T" + this.time + "Z";
|
||||
this.time = utcDate.toFormat("HH:mm:ss");
|
||||
|
||||
this.model.TakenAt = utcDate;
|
||||
|
||||
this.time = DateTime.fromISO(this.model.TakenAt).toUTC().toFormat("HH:mm:ss");
|
||||
|
||||
let localDate = DateTime.fromISO(utcDate);
|
||||
let localDate = utcDate;
|
||||
|
||||
if (this.model.TimeZone) {
|
||||
localDate = localDate.setZone(this.model.TimeZone);
|
||||
} else {
|
||||
localDate = localDate.toUTC(0);
|
||||
}
|
||||
|
||||
this.model.TakenAtLocal = localDate.toISO({
|
||||
|
@ -498,7 +492,19 @@
|
|||
includeOffset: false,
|
||||
}) + "Z";
|
||||
|
||||
this.timeLocalFormatted = localDate.toLocaleString(DateTime.TIME_24_WITH_SECONDS);
|
||||
if(this.model.Day === 0) {
|
||||
this.model.Day = parseInt(localDate.toFormat("d"));
|
||||
}
|
||||
|
||||
if(this.model.Month === 0) {
|
||||
this.model.Month = parseInt(localDate.toFormat("L"));
|
||||
}
|
||||
|
||||
if(this.model.Year === 0) {
|
||||
this.model.Year = parseInt(localDate.toFormat("y"));
|
||||
}
|
||||
|
||||
this.localTime = localDate.toLocaleString(DateTime.TIME_24_WITH_SECONDS);
|
||||
},
|
||||
left() {
|
||||
this.$emit('next');
|
||||
|
@ -509,21 +515,8 @@
|
|||
openPhoto() {
|
||||
this.$viewer.show(Thumb.fromFiles([this.model]), 0)
|
||||
},
|
||||
refresh(model) {
|
||||
if (!model.hasId()) return;
|
||||
|
||||
if (model.TakenAt) {
|
||||
const date = DateTime.fromISO(model.TakenAt).toUTC();
|
||||
this.date = date.toISODate();
|
||||
this.time = date.toFormat("HH:mm:ss");
|
||||
|
||||
this.updateTime();
|
||||
}
|
||||
},
|
||||
save(close) {
|
||||
if (this.time && this.date) {
|
||||
this.model.TakenAt = this.date + "T" + this.time + "Z";
|
||||
}
|
||||
this.model.TakenAt = this.model.isoDate(this.time);
|
||||
|
||||
this.model.update().then(() => {
|
||||
if (close) {
|
||||
|
|
|
@ -54,35 +54,6 @@
|
|||
</td>
|
||||
<td>{{ model.TitleSrc | capitalize }}</td>
|
||||
</tr>
|
||||
<tr v-if="model.TakenAcc">
|
||||
<td>
|
||||
<translate key="Year">Year</translate>
|
||||
</td>
|
||||
<td>
|
||||
<v-text-field
|
||||
flat solo dense hide-details v-model="model.Year"
|
||||
color="secondary-dark"
|
||||
style="font-weight: 400; font-size: 13px;"
|
||||
></v-text-field>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="model.TakenAcc">
|
||||
<td>
|
||||
<translate key="Month">Month</translate>
|
||||
</td>
|
||||
<td>
|
||||
<v-select
|
||||
label="Month"
|
||||
flat solo dense hide-details
|
||||
color="secondary-dark"
|
||||
style="font-weight: 400; font-size: 13px;"
|
||||
item-value="Month"
|
||||
item-text="Name"
|
||||
v-model="model.Month"
|
||||
:items="monthOptions">
|
||||
</v-select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<translate key="Quality Score">Quality Score</translate>
|
||||
|
|
|
@ -44,6 +44,7 @@ export const TypeJpeg = "jpg";
|
|||
export const TypeImage = "image";
|
||||
export const YearUnknown = -1;
|
||||
export const MonthUnknown = -1;
|
||||
export const DayUnknown = -1;
|
||||
|
||||
export class Photo extends RestModel {
|
||||
getDefaults() {
|
||||
|
@ -57,7 +58,6 @@ export class Photo extends RestModel {
|
|||
TakenAt: "",
|
||||
TakenAtLocal: "",
|
||||
TakenSrc: "",
|
||||
TakenAcc: 0,
|
||||
TimeZone: "",
|
||||
Path: "",
|
||||
Color: "",
|
||||
|
@ -86,6 +86,7 @@ export class Photo extends RestModel {
|
|||
Country: "",
|
||||
Year: YearUnknown,
|
||||
Month: MonthUnknown,
|
||||
Day: DayUnknown,
|
||||
Details: {
|
||||
Keywords: "",
|
||||
Notes: "",
|
||||
|
@ -124,6 +125,48 @@ export class Photo extends RestModel {
|
|||
};
|
||||
}
|
||||
|
||||
isoDay() {
|
||||
if(!this.Day || this.Day <= 0) {
|
||||
return this.TakenAt.substr(8, 2);
|
||||
}
|
||||
|
||||
return this.Day.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
isoMonth() {
|
||||
if(!this.Month || this.Month <= 0) {
|
||||
return this.TakenAt.substr(5, 2);
|
||||
}
|
||||
|
||||
return this.Month.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
isoYear() {
|
||||
if(!this.Year || this.Year <= 1000) {
|
||||
return this.TakenAt.substr(0, 4);
|
||||
}
|
||||
|
||||
return this.Year.toString();
|
||||
}
|
||||
|
||||
isoDate(time) {
|
||||
if(!this.isoYear()) {
|
||||
return this.TakenAt;
|
||||
}
|
||||
|
||||
let date = this.isoYear() + "-" + this.isoMonth() + "-" + this.isoDay();
|
||||
|
||||
if(!time) {
|
||||
time = this.TakenAt.substr(11, 8);
|
||||
}
|
||||
|
||||
return `${date}T${time}Z`;
|
||||
}
|
||||
|
||||
utcDate() {
|
||||
return DateTime.fromISO(this.TakenAt).toUTC();
|
||||
}
|
||||
|
||||
baseName(truncate) {
|
||||
let result = this.fileBase(this.FileName ? this.FileName : this.mainFile().Name);
|
||||
|
||||
|
|
|
@ -1,19 +1,60 @@
|
|||
import {$gettext} from "common/vm";
|
||||
import moment from "moment-timezone";
|
||||
import {Info} from "luxon";
|
||||
import {config} from "../session";
|
||||
|
||||
export const TimeZones = () => moment.tz.names();
|
||||
|
||||
export const Days = () => {
|
||||
let result = [];
|
||||
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
result.push({"value": i, "text": i.toString().padStart(2, "0")});
|
||||
}
|
||||
|
||||
result.push({"value": -1, "text": $gettext("Unknown")});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const Years = () => {
|
||||
let result = [];
|
||||
|
||||
const currentYear = new Date().getUTCFullYear();
|
||||
|
||||
for (let i = currentYear; i >= 1750; i--) {
|
||||
result.push({"value": i, "text": i.toString().padStart(4, "0")});
|
||||
}
|
||||
|
||||
result.push({"value": -1, "text": $gettext("Unknown")});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const IndexedYears = () => {
|
||||
let result = [];
|
||||
|
||||
if (config.values.years) {
|
||||
for (let i = 0; i < config.values.years.length; i++) {
|
||||
result.push({"value": parseInt(config.values.years[i]), "text": config.values.years[i].toString()});
|
||||
}
|
||||
}
|
||||
|
||||
result.push({"value": -1, "text": $gettext("Unknown")});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const Months = () => {
|
||||
let result = [];
|
||||
|
||||
const months = Info.months("long");
|
||||
|
||||
for (let i = 0; i < months.length; i++) {
|
||||
result.push({"Month": i + 1, "Name": months[i]});
|
||||
result.push({"value": i + 1, "text": months[i]});
|
||||
}
|
||||
|
||||
result.push({"Month": -1, "Name": $gettext("Unknown")});
|
||||
result.push({"value": -1, "text": $gettext("Unknown")});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@ type Album struct {
|
|||
AlbumCountry string `gorm:"type:varbinary(2);index:idx_albums_country_year_month;default:'zz'" json:"Country" yaml:"Country,omitempty"`
|
||||
AlbumYear int `gorm:"index:idx_albums_country_year_month;" json:"Year" yaml:"Year,omitempty"`
|
||||
AlbumMonth int `gorm:"index:idx_albums_country_year_month;" json:"Month" yaml:"Month,omitempty"`
|
||||
AlbumDay int `json:"Day" yaml:"Day,omitempty"`
|
||||
AlbumFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
|
||||
AlbumPrivate bool `json:"Private" yaml:"Private,omitempty"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
|
|
|
@ -25,6 +25,7 @@ const (
|
|||
// Unknown values.
|
||||
YearUnknown = -1
|
||||
MonthUnknown = -1
|
||||
DayUnknown = -1
|
||||
TitleUnknown = "Unknown"
|
||||
|
||||
// Content types.
|
||||
|
|
|
@ -38,6 +38,9 @@ type Person struct {
|
|||
CanDownload bool `json:"CanDownload" yaml:"CanDownload,omitempty"`
|
||||
WebDAV bool `gorm:"column:webdav" json:"WebDAV" yaml:"WebDAV,omitempty"`
|
||||
ApiToken string `json:"ApiToken" yaml:"ApiToken,omitempty"`
|
||||
BirthYear int `json:"BirthYear" yaml:"BirthYear,omitempty"`
|
||||
BirthMonth int `json:"BirthMonth" yaml:"BirthMonth,omitempty"`
|
||||
BirthDay int `json:"BirthDay" yaml:"BirthDay,omitempty"`
|
||||
LoginAttempts int `json:"-" yaml:"-,omitempty"`
|
||||
LoginAt *time.Time `json:"-" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
|
|
|
@ -37,7 +37,6 @@ type Photo struct {
|
|||
TakenAt time.Time `gorm:"type:datetime;index:idx_photos_taken_uid;" json:"TakenAt" yaml:"TakenAt"`
|
||||
TakenAtLocal time.Time `gorm:"type:datetime;" yaml:"-"`
|
||||
TakenSrc string `gorm:"type:varbinary(8);" json:"TakenSrc" yaml:"TakenSrc,omitempty"`
|
||||
TakenAcc int `json:"TakenAcc" yaml:"TakenAcc,omitempty"`
|
||||
PhotoUID string `gorm:"type:varbinary(42);unique_index;index:idx_photos_taken_uid;" json:"UID" yaml:"UID"`
|
||||
PhotoType string `gorm:"type:varbinary(8);default:'image';" json:"Type" yaml:"Type"`
|
||||
PhotoTitle string `gorm:"type:varchar(255);" json:"Title" yaml:"Title"`
|
||||
|
@ -60,8 +59,9 @@ type Photo struct {
|
|||
PhotoLng float32 `gorm:"type:FLOAT;index;" json:"Lng" yaml:"Lng,omitempty"`
|
||||
PhotoAltitude int `json:"Altitude" yaml:"Altitude,omitempty"`
|
||||
PhotoCountry string `gorm:"type:varbinary(2);index:idx_photos_country_year_month;default:'zz'" json:"Country" yaml:"-"`
|
||||
PhotoYear int `gorm:"index:idx_photos_country_year_month;" json:"Year" yaml:"-"`
|
||||
PhotoMonth int `gorm:"index:idx_photos_country_year_month;" json:"Month" yaml:"-"`
|
||||
PhotoYear int `gorm:"index:idx_photos_country_year_month;" json:"Year" yaml:"Year"`
|
||||
PhotoMonth int `gorm:"index:idx_photos_country_year_month;" json:"Month" yaml:"Month"`
|
||||
PhotoDay int `json:"Day" yaml:"Day"`
|
||||
PhotoIso int `json:"Iso" yaml:"ISO,omitempty"`
|
||||
PhotoExposure string `gorm:"type:varbinary(64);" json:"Exposure" yaml:"Exposure,omitempty"`
|
||||
PhotoFNumber float32 `gorm:"type:FLOAT;" json:"FNumber" yaml:"FNumber,omitempty"`
|
||||
|
@ -111,7 +111,7 @@ func SavePhotoForm(model Photo, form form.Photo, geoApi string) error {
|
|||
return errors.New("photo: can't save form, id is empty")
|
||||
}
|
||||
|
||||
model.UpdateYearMonth()
|
||||
model.UpdateDateFields()
|
||||
|
||||
if form.Details.PhotoID == model.ID {
|
||||
if err := deepcopier.Copy(&model.Details).From(form.Details); err != nil {
|
||||
|
@ -182,7 +182,7 @@ func (m *Photo) Save() error {
|
|||
|
||||
labels := m.ClassifyLabels()
|
||||
|
||||
m.UpdateYearMonth()
|
||||
m.UpdateDateFields()
|
||||
|
||||
if err := m.UpdateTitle(labels); err != nil {
|
||||
log.Info(err)
|
||||
|
@ -735,11 +735,11 @@ func (m *Photo) SetTakenAt(taken, local time.Time, zone, source string) {
|
|||
m.TimeZone = zone
|
||||
}
|
||||
|
||||
m.UpdateYearMonth()
|
||||
m.UpdateDateFields()
|
||||
}
|
||||
|
||||
// UpdateYearMonth updates internal date fields.
|
||||
func (m *Photo) UpdateYearMonth() {
|
||||
// UpdateDateFields updates internal date fields.
|
||||
func (m *Photo) UpdateDateFields() {
|
||||
if m.TakenAt.IsZero() || m.TakenAt.Year() < 1000 {
|
||||
return
|
||||
}
|
||||
|
@ -751,9 +751,11 @@ func (m *Photo) UpdateYearMonth() {
|
|||
if m.TakenSrc == SrcAuto {
|
||||
m.PhotoYear = YearUnknown
|
||||
m.PhotoMonth = MonthUnknown
|
||||
} else {
|
||||
m.PhotoDay = DayUnknown
|
||||
} else if m.TakenSrc != SrcManual {
|
||||
m.PhotoYear = m.TakenAtLocal.Year()
|
||||
m.PhotoMonth = int(m.TakenAtLocal.Month())
|
||||
m.PhotoDay = m.TakenAtLocal.Day()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ func (m *Photo) Optimize() (updated bool, err error) {
|
|||
|
||||
labels := m.ClassifyLabels()
|
||||
|
||||
m.UpdateYearMonth()
|
||||
m.UpdateDateFields()
|
||||
|
||||
if err := m.UpdateTitle(labels); err != nil {
|
||||
log.Info(err)
|
||||
|
|
|
@ -11,6 +11,7 @@ type AlbumSearch struct {
|
|||
Country string `json:"country"`
|
||||
Year int `json:"year"`
|
||||
Month int `json:"month"`
|
||||
Day int `json:"day"`
|
||||
Favorite bool `form:"favorite"`
|
||||
Private bool `form:"private"`
|
||||
Count int `form:"count" binding:"required" serialize:"-"`
|
||||
|
|
|
@ -22,8 +22,10 @@ type Photo struct {
|
|||
TakenAt time.Time `json:"TakenAt"`
|
||||
TakenAtLocal time.Time `json:"TakenAtLocal"`
|
||||
TakenSrc string `json:"TakenSrc"`
|
||||
TakenAcc int `json:"TakenAcc"`
|
||||
TimeZone string `json:"TimeZone"`
|
||||
PhotoYear int `json:"Year"`
|
||||
PhotoMonth int `json:"Month"`
|
||||
PhotoDay int `json:"Day"`
|
||||
PhotoTitle string `json:"Title"`
|
||||
TitleSrc string `json:"TitleSrc"`
|
||||
PhotoDescription string `json:"Description"`
|
||||
|
|
|
@ -46,6 +46,7 @@ type PhotoSearch struct {
|
|||
State string `form:"state"` // Moments
|
||||
Year int `form:"year"` // Moments
|
||||
Month int `form:"month"` // Moments
|
||||
Day int `form:"day"` // Moments
|
||||
Color string `form:"color"`
|
||||
Quality int `form:"quality"`
|
||||
Review bool `form:"review"`
|
||||
|
|
|
@ -466,7 +466,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
|
|||
photo.PlaceID = entity.UnknownPlace.ID
|
||||
}
|
||||
|
||||
photo.UpdateYearMonth()
|
||||
photo.UpdateDateFields()
|
||||
|
||||
file.FileSidecar = m.IsSidecar()
|
||||
file.FileVideo = m.IsVideo()
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/capture"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// AlbumResult contains found albums
|
||||
|
@ -29,6 +30,7 @@ type AlbumResult struct {
|
|||
AlbumCountry string `json:"Country"`
|
||||
AlbumYear int `json:"Year"`
|
||||
AlbumMonth int `json:"Month"`
|
||||
AlbumDay int `json:"Day"`
|
||||
AlbumFavorite bool `json:"Favorite"`
|
||||
AlbumPrivate bool `json:"Private"`
|
||||
PhotoCount int `json:"PhotoCount"`
|
||||
|
@ -138,11 +140,23 @@ func AlbumSearch(f form.AlbumSearch) (results AlbumResults, err error) {
|
|||
s = s.Where("albums.album_favorite = 1")
|
||||
}
|
||||
|
||||
if (f.Year > 0 && f.Year <= txt.YearMax) || f.Year == entity.YearUnknown {
|
||||
s = s.Where("albums.album_year = ?", f.Year)
|
||||
}
|
||||
|
||||
if (f.Month >= txt.MonthMin && f.Month <= txt.MonthMax) || f.Month == entity.MonthUnknown {
|
||||
s = s.Where("albums.album_month = ?", f.Month)
|
||||
}
|
||||
|
||||
if (f.Day >= txt.DayMin && f.Month <= txt.DayMax) || f.Day == entity.DayUnknown {
|
||||
s = s.Where("albums.album_day = ?", f.Day)
|
||||
}
|
||||
|
||||
switch f.Order {
|
||||
case "slug":
|
||||
s = s.Order("albums.album_favorite DESC, album_slug ASC")
|
||||
default:
|
||||
s = s.Order("albums.album_favorite DESC, albums.album_year DESC, albums.album_month DESC, albums.album_title, albums.created_at DESC")
|
||||
s = s.Order("albums.album_favorite DESC, albums.album_year DESC, albums.album_month DESC, albums.album_day DESC, albums.album_title, albums.created_at DESC")
|
||||
}
|
||||
|
||||
if f.Count > 0 && f.Count <= MaxResults {
|
||||
|
|
|
@ -20,7 +20,6 @@ type PhotoResult struct {
|
|||
TakenAt time.Time `json:"TakenAt"`
|
||||
TakenAtLocal time.Time `json:"TakenAtLocal"`
|
||||
TakenSrc string `json:"TakenSrc"`
|
||||
TakenAcc int `json:"TakenAcc"`
|
||||
TimeZone string `json:"TimeZone"`
|
||||
PhotoPath string `json:"Path"`
|
||||
PhotoName string `json:"Name"`
|
||||
|
@ -29,6 +28,7 @@ type PhotoResult struct {
|
|||
PhotoDescription string `json:"Description"`
|
||||
PhotoYear int `json:"Year"`
|
||||
PhotoMonth int `json:"Month"`
|
||||
PhotoDay int `json:"Day"`
|
||||
PhotoCountry string `json:"Country"`
|
||||
PhotoFavorite bool `json:"Favorite"`
|
||||
PhotoPrivate bool `json:"Private"`
|
||||
|
|
|
@ -178,6 +178,10 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error
|
|||
s = s.Where("photos.photo_month = ?", f.Month)
|
||||
}
|
||||
|
||||
if (f.Day >= txt.DayMin && f.Month <= txt.DayMax) || f.Day == entity.DayUnknown {
|
||||
s = s.Where("photos.photo_day = ?", f.Day)
|
||||
}
|
||||
|
||||
if f.Color != "" {
|
||||
s = s.Where("files.file_main_color IN (?)", strings.Split(strings.ToLower(f.Color), ","))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue