mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-01-31 07:11:33 +00:00
feat: filter uploads using relative time duration
added a new production dependency parse-duration@~1.0.2 read filters help popup in dashboard for usage example
This commit is contained in:
parent
94cfb8617c
commit
aebeb8e045
@ -1,6 +1,7 @@
|
||||
const blake3 = require('blake3')
|
||||
const contentDisposition = require('content-disposition')
|
||||
const fs = require('fs')
|
||||
const parseDuration = require('parse-duration')
|
||||
const path = require('path')
|
||||
const randomstring = require('randomstring')
|
||||
const searchQuery = require('search-query-parser')
|
||||
@ -1219,6 +1220,12 @@ self.list = async (req, res) => {
|
||||
const MAX_SORT_KEYS = 2
|
||||
const MAX_IS_KEYS = 1
|
||||
|
||||
// Timezone offset
|
||||
let timezoneOffset = 0
|
||||
if (minoffset !== undefined) {
|
||||
timezoneOffset = 60000 * (utils.timezoneOffset - minoffset)
|
||||
}
|
||||
|
||||
const filterObj = {
|
||||
uploaders: [],
|
||||
excludeUploaders: [],
|
||||
@ -1388,17 +1395,12 @@ self.list = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
const parseDate = (date, minoffset, resetMs) => {
|
||||
let offset = 0
|
||||
if (minoffset !== undefined) {
|
||||
offset = 60000 * (utils.timezoneOffset - minoffset)
|
||||
}
|
||||
|
||||
const parseDate = (date, resetMs) => {
|
||||
// [YYYY][/MM][/DD] [HH][:MM][:SS]
|
||||
// e.g. 2020/01/01 00:00:00, 2018/01/01 06, 2019/11, 12:34:00
|
||||
const formattedMatch = date.match(/^(\d{4})?(\/\d{2})?(\/\d{2})?\s?(\d{2})?(:\d{2})?(:\d{2})?$/)
|
||||
if (formattedMatch) {
|
||||
const dateObj = new Date(Date.now() + offset)
|
||||
const dateObj = new Date(Date.now() + timezoneOffset)
|
||||
|
||||
if (formattedMatch[1] !== undefined) {
|
||||
dateObj.setFullYear(Number(formattedMatch[1]), // full year
|
||||
@ -1417,24 +1419,58 @@ self.list = async (req, res) => {
|
||||
}
|
||||
|
||||
// Calculate timezone differences
|
||||
return new Date(dateObj.getTime() - offset)
|
||||
} else if (/^\d+/.test(date)) {
|
||||
return new Date(dateObj.getTime() - timezoneOffset)
|
||||
} else if (/^\d+$/.test(date)) {
|
||||
// Unix timestamps (always assume seconds resolution)
|
||||
return new Date(parseInt(date) * 1000)
|
||||
} else {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const parseRelativeDuration = (operator, duration, resetMs, inverse = false) => {
|
||||
let milliseconds = parseDuration(duration)
|
||||
if (isNaN(milliseconds) || typeof milliseconds !== 'number') {
|
||||
return null
|
||||
}
|
||||
|
||||
let from = operator === '<'
|
||||
if (inverse) {
|
||||
// Intended for "expiry" column, as it essentially has to do the opposite
|
||||
from = !from
|
||||
milliseconds = -milliseconds
|
||||
}
|
||||
|
||||
const dateObj = new Date(Date.now() + timezoneOffset - milliseconds)
|
||||
if (resetMs) {
|
||||
dateObj.setMilliseconds(0)
|
||||
}
|
||||
|
||||
const range = { from: null, to: null }
|
||||
const offsetDateObj = new Date(dateObj.getTime() - timezoneOffset)
|
||||
if (from) {
|
||||
range.from = Math.floor(offsetDateObj / 1000)
|
||||
} else {
|
||||
range.to = Math.ceil(offsetDateObj / 1000)
|
||||
}
|
||||
return range
|
||||
}
|
||||
|
||||
// Parse dates to timestamps
|
||||
for (const range of ranges) {
|
||||
if (filterObj.queries[range]) {
|
||||
if (filterObj.queries[range].from) {
|
||||
const parsed = parseDate(filterObj.queries[range].from, minoffset, true)
|
||||
const relativeMatch = filterObj.queries[range].from.match(/^(<|>)(.*)$/)
|
||||
if (relativeMatch && relativeMatch[2]) {
|
||||
// Human-readable relative duration
|
||||
filterObj.queries[range] = parseRelativeDuration(relativeMatch[1], relativeMatch[2], true, (range === 'expiry'))
|
||||
continue
|
||||
} else {
|
||||
const parsed = parseDate(filterObj.queries[range].from, true)
|
||||
filterObj.queries[range].from = parsed ? Math.floor(parsed / 1000) : null
|
||||
}
|
||||
}
|
||||
if (filterObj.queries[range].to) {
|
||||
const parsed = parseDate(filterObj.queries[range].to, minoffset, true)
|
||||
const parsed = parseDate(filterObj.queries[range].to, true)
|
||||
filterObj.queries[range].to = parsed ? Math.ceil(parsed / 1000) : null
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@
|
||||
"markdown-it": "~13.0.1",
|
||||
"node-fetch": "~2.6.7",
|
||||
"nunjucks": "~3.2.3",
|
||||
"parse-duration": "~1.0.2",
|
||||
"randomstring": "~1.2.2",
|
||||
"range-parser": "~1.2.1",
|
||||
"rate-limiter-flexible": "~2.3.10",
|
||||
|
@ -1163,14 +1163,14 @@ page.uploadFiltersHelp = element => {
|
||||
Negation sign can also be used to exclude uploads with no albums (i.e. <code>-albumid:-</code>).`}
|
||||
|
||||
There are 2 range keys: <b>date</b> (upload date) and <b>expiry</b> (expiry date).
|
||||
Their format is: <code>"YYYY/MM/DD HH:MM:SS-YYYY/MM/DD HH:MM:SS"</code> ("from" date and "to" date respectively),
|
||||
OR unix timestamps in seconds resolution.
|
||||
Their formats are: <code>"YYYY/MM/DD HH:MM:SS-YYYY/MM/DD HH:MM:SS"</code> ("from" date and "to" date respectively),
|
||||
unix timestamps in seconds resolution, OR human-readable relative time duration (<a href="https://github.com/jkroso/parse-duration/tree/50ebcc8a971c753bd1162332ccf5f3ef1e0b3a7e#available-unit-types-are" target="_blank" rel="noopener">available units</a>).
|
||||
You may choose to specify only either dates.
|
||||
If "to" date is missing, 'now' will be used. If "from" date is missing, 'beginning of time' will be used.
|
||||
If any of the subsequent date or time units are not specified, their first value will be used (e.g. January for month, 1 for day, and so on).
|
||||
If only time is specified, today's date will be used.
|
||||
If you do not need to specify both date and time, you may omit the double quotes.
|
||||
In conclusion, the following examples are all valid: <code>date:"2020/01/01 01:23-2018/01/01 06"</code>, <code>expiry:-2020/05</code>, <code>date:12:34:56</code>.
|
||||
In conclusion, the following examples are all valid: <code>date:"2020/01/01 01:23-2018/01/01 06"</code>, <code>expiry:-2020/05</code>, <code>date:12:34:56</code>, <code>date:1663976000</code>, <code>date:<7days</code>.
|
||||
<b>date</b> and <b>expiry</b> keys can only be specified once each.
|
||||
|
||||
<b>What about timezones?</b>
|
||||
@ -1224,6 +1224,12 @@ page.uploadFiltersHelp = element => {
|
||||
<code>date:"2020/04/07 12-2020/04/07 23:59:59"</code>
|
||||
- Uploads uploaded before "5 February 2020 00:00:00":
|
||||
<code>date:-2020/02/05</code>
|
||||
- Uploads uploaded within the last 24 hours (1 day):
|
||||
<code>date:<1d</code>
|
||||
- Uploads uploaded before the last 6 months:
|
||||
<code>date:>6months</code>
|
||||
- Uploads that will expire within the next 7 days and 12 hours:
|
||||
<code>expiry:"<7 days 12 hours"</code>
|
||||
- Uploads which file names match "*.gz" but NOT "*.tar.gz":
|
||||
<code>*.gz -*.tar.gz</code>
|
||||
- Sort matches by "size" column in ascending and descending order respectively:
|
||||
|
@ -4365,6 +4365,11 @@ parent-module@^1.0.0:
|
||||
dependencies:
|
||||
callsites "^3.0.0"
|
||||
|
||||
parse-duration@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-1.0.2.tgz#b9aa7d3a1363cc7e8845bea8fd3baf8a11df5805"
|
||||
integrity sha512-Dg27N6mfok+ow1a2rj/nRjtCfaKrHUZV2SJpEn/s8GaVUSlf4GGRCRP1c13Hj+wfPKVMrFDqLMLITkYKgKxyyg==
|
||||
|
||||
parse-filepath@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
|
||||
|
Loading…
Reference in New Issue
Block a user