Skip to content

Commit

Permalink
Support Webtime Tracker (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheepzh committed Jul 24, 2023
1 parent 70ef69c commit b808fe6
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import StatDatabase from "@db/stat-database"
import { AUTHOR_EMAIL } from "@src/package"
import { isNotZeroResult } from "@util/stat"

const statDatabase: StatDatabase = new StatDatabase(chrome.storage.local)

export type OtherExtension = "web_activity_time_tracker"
export type OtherExtension = "webtime_tracker" | "web_activity_time_tracker"

export type ActionType = 'overwrite' | 'accumulate'

Expand All @@ -18,6 +19,8 @@ export type ImportedData = {
rows: ImportedRow[]
}

const throwError = () => { throw new Error("Failed to parse, please check your file or contact the author via " + AUTHOR_EMAIL) }

/**
* Parse the content to rows
*
Expand All @@ -26,20 +29,18 @@ export type ImportedData = {
* @returns row data
*/
export async function parseFile(ext: OtherExtension, file: File): Promise<ImportedData> {
const text = await file.text()
let rows: ImportedRow[] = []
let focus = false
let time = false
if (ext === 'web_activity_time_tracker') {
const lines = text.split('\n').map(line => line.trim()).filter(line => !!line).splice(1)
const rows: ImportedRow[] = lines.map(line => {
const [host, date, seconds] = line.split(',').map(cell => cell.trim())
const [year, month, day] = date.split('/')
const realDate = `${year}${month.length == 2 ? month : '0' + month}${day.length == 2 ? day : '0' + day}`
return { host, date: realDate, focus: parseInt(seconds) * 1000 }
})
await doIfExist(rows, (row, exist) => row.exist = exist)
return { rows, focus: true }
} else {
return { rows: [] }
rows = await parseWebActivityTimeTracker(file)
focus = true
} else if (ext === 'webtime_tracker') {
rows = await parseWebtimeTracker(file)
focus = true
}
await doIfExist(rows, (row, exist) => row.exist = exist)
return { rows, focus, time }
}

async function doIfExist<T extends timer.stat.RowKey>(items: T[], processor: (item: T, existVal: timer.stat.Result) => any): Promise<void> {
Expand All @@ -50,6 +51,79 @@ async function doIfExist<T extends timer.stat.RowKey>(items: T[], processor: (it
}))
}

async function parseWebActivityTimeTracker(file: File): Promise<ImportedRow[]> {
const text = await file.text()
const lines = text.split('\n').map(line => line.trim()).filter(line => !!line).splice(1)
const rows: ImportedRow[] = lines.map(line => {
const [host, date, seconds] = line.split(',').map(cell => cell.trim())
!host || !date || (!seconds && seconds !== '0') && throwError()
const [year, month, day] = date.split('/')
!year || !month || !day && throwError()
const realDate = `${year}${month.length == 2 ? month : '0' + month}${day.length == 2 ? day : '0' + day}`
return { host, date: realDate, focus: parseInt(seconds) * 1000 }
})
return rows
}

type WebtimeTrackerBackup = {
content: {
domains: {
[domain: string]: {
name: string
days: {
// date format: 2023-07-22
[date: string]: { seconds: number }
}
}
}
}
}

const WEBTIME_TRACKER_DATE_REG = /(\d{2})-(\d{2})-\d{2}/
const cvtWebtimeTrackerDate = (date: string): string => WEBTIME_TRACKER_DATE_REG.test(date) ? date.split('-').join('') : undefined

async function parseWebtimeTracker(file: File): Promise<ImportedRow[]> {
const text = await file.text()
if (isJsonFile(file)) {
// JSON file by backup
const data = JSON.parse(text) as WebtimeTrackerBackup
const domains = data?.content?.domains || {}
const rows: ImportedRow[] = Object.entries(domains)
.flatMap(
([host, value]) => Object.entries(value?.days || {})
.map(([date, item]) => [host, cvtWebtimeTrackerDate(date), item?.seconds] as [string, string, number])
)
.filter(([host, date, seconds]) => host && date && seconds)
.map(([host, date, seconds]) => ({
host,
date,
focus: seconds * 1000
} as ImportedRow))
console.log(rows)
return rows
} else if (isCsvFile(file)) {
const lines = text.split('\n').map(line => line.trim()).filter(line => !!line)
const colHeaders = lines[0].split(',')
const rows: ImportedRow[] = []
lines.slice(1).forEach(line => {
const cells = line.split(',')
const host = cells[0]
if (!host) return
for (let i = 1; i < colHeaders?.length; i++) {
const seconds = Number.parseInt(cells[i])
const date = cvtWebtimeTrackerDate(colHeaders[i])
seconds && date && rows.push({ host, date, focus: seconds * 1000 })
}
})
return rows
}
throw new Error("Invalid file format")
}

const isJsonFile = (file: File): boolean => file?.type?.startsWith('application/json')

const isCsvFile = (file: File): boolean => file?.type?.startsWith('text/csv')

/**
* Import data
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { Document, Close, Right } from "@element-plus/icons-vue"
import { ImportedData, OtherExtension, parseFile } from "./processor"

const OTHER_NAMES: { [ext in OtherExtension]: string } = {
webtime_tracker: "Webtime Tracker",
web_activity_time_tracker: "Web Activity Time Tracker"
}

const OTHER_FILE_FORMAT: { [ext in OtherExtension]: string } = {
web_activity_time_tracker: '.csv'
webtime_tracker: '.csv,.json',
web_activity_time_tracker: '.csv',
}

const ALL_TYPES: OtherExtension[] = Object.keys(OTHER_NAMES) as OtherExtension[]
Expand All @@ -20,7 +22,7 @@ const _default = defineComponent({
next: (_rows: ImportedData) => true,
},
setup(_, ctx) {
const type: Ref<OtherExtension> = ref('web_activity_time_tracker')
const type: Ref<OtherExtension> = ref('webtime_tracker')
const selectedFile: Ref<File> = ref()
const fileInput: Ref<HTMLInputElement> = ref()
const fileParsing: Ref<boolean> = ref(false)
Expand Down

0 comments on commit b808fe6

Please sign in to comment.