Skip to content

Instantly share code, notes, and snippets.

@benoitjadinon
Last active March 4, 2026 18:42
Show Gist options
  • Select an option

  • Save benoitjadinon/58616ddaa3b5480bedae761ed24c7447 to your computer and use it in GitHub Desktop.

Select an option

Save benoitjadinon/58616ddaa3b5480bedae761ed24c7447 to your computer and use it in GitHub Desktop.
Subscriptions obsidian base
model:
version: 1
kind: Table
columns: []
pluginVersion: 1.0.0
summaries:
Unique: values.unique().length
Total: values.reduce(number(acc)+number(value), 0).toFixed(2)
filters:
and:
- file.ext == "md"
- file.basename != this.file.basename
- or:
- file.folder.endsWith("Subscriptions")
- file.tags.containsAny("subscription", "subscriptions")
- and:
- '!file.basename.endsWith("Template")'
- '!file.folder.endsWith("Templates")'
formulas:
icon: if (favicon || icon || url, image(if(favicon, favicon, if(icon, icon, "https://www.google.com/s2/favicons?domain="+url))))
enabled: endDate>=now().date() || formula.isRenewing
priceAdjusted: (price+formula.sharedAdjustment).toFixed(2)
sharedAdjustment: (number(if(note["share-price"], -number(note["share-price"]) * shared, 0)))
targetDate: if(endDate, endDate, today())
monthsDiff: (number(date(formula.targetDate).format("YYYY")) - number(date(startDate).format("YYYY"))) * 12 + (number(date(formula.targetDate).format("MM")) - number(date(startDate).format("MM")))
yearsDiff: number(date(formula.targetDate).format("YYYY")) - number(date(startDate).format("YYYY"))
hasPassedDayThisMonth: number(date(formula.targetDate).format("DD")) >= number(date(startDate).format("DD"))
hasPassedMonthThisYear: number(date(formula.targetDate).format("MM")) > number(date(startDate).format("MM")) || (number(date(formula.targetDate).format("MM")) == number(date(startDate).format("MM")) && formula.hasPassedDayThisMonth)
monthsStarted: if(startDate > formula.targetDate, 0, if(formula.hasPassedDayThisMonth, formula.monthsDiff, formula.monthsDiff - 1))
yearsStarted: if(startDate > formula.targetDate, 0, if(formula.hasPassedMonthThisYear, formula.yearsDiff, formula.yearsDiff - 1))
cyclesStarted: |-
if(cycle.endsWith("d"),
((formula.targetDate - startDate).days / number(cycle.slice(0, -1))).floor(),
if(cycle == "1M",
formula.monthsStarted,
if(cycle.endsWith("M"),
((formula.targetDate - startDate).days / (number(cycle) * 30.44)).floor(),
if(cycle == "1Y",
formula.yearsStarted,
if(cycle.endsWith("y"),
((formula.targetDate - startDate).days / (number(cycle) * 365.25)).floor(),
(formula.targetDate - startDate).days
)
)
)
)
)
cyclesNext: |-
if(cycle.endsWith("d"),
((formula.targetDate - startDate).days / number(cycle.slice(0, -1))).ceil(),
if(cycle == "1M",
if(startDate > formula.targetDate, 1, formula.monthsStarted + 1),
if(cycle.endsWith("M"),
((formula.targetDate - startDate).days / (number(cycle) * 30.44)).ceil(),
if(cycle == "1Y",
if(startDate > formula.targetDate, 1, formula.yearsStarted + 1),
if(cycle.endsWith("y"),
((formula.targetDate - startDate).days / (number(cycle) * 365.25)).ceil(),
(formula.targetDate - startDate).days
)
)
)
)
)
nextPaymentDate: |-
if(cycle == "lifetime", 'never',
if(startDate > now(), startDate,
if(endDate && endDate < now(), endDate,
if(cycle.endsWith("d"),
startDate + ((formula.cyclesNext * number(cycle.slice(0, -1))).ceil() + "d"),
startDate + formula.cycleNextDuration
)
)
)
)
cycleNextDuration: |-
if(cycle.endsWith("d"),
(formula.cyclesNext * number(cycle.slice(0, -1))).ceil() + "d",
if(cycle.endsWith("M"),
(formula.cyclesNext * number(cycle.slice(0, -1))) + "M",
if(cycle.endsWith("y") || cycle.endsWith("Y"),
(formula.cyclesNext * number(cycle.slice(0, -1))) + "y",
formula.cyclesNext + "d"
)
)
)
started: startDate.relative()
duration: if (endDate, endDate, today())-startDate
nextPaymentDuration: if (formula.nextPaymentDate, if (date(formula.nextPaymentDate).date() == today(), "TODAY",date(formula.nextPaymentDate).relative()), "")
isRenewing: endDate.isEmpty()
status: |-
if(cycle == "lifetime",
'lifetime',
if (startDate > now(),
"starts",
if (formula.isRenewing, "renews", if (endDate > now(), "ends", "ended"))
)+" "+formula.nextPaymentDuration
)
nextPaymentDays: |-
if(cycle == "lifetime", 0,
if(formula.nextPaymentDate, number((date(formula.nextPaymentDate)-today()).days.round(0)), 0)
)
cycleDays: |-
if(cycle == "lifetime", 'lifetime',
(date("1970-01-01")-formula.cycleDaysRounded-date("1970-01-01")).days.abs()
)
pricePerMonth: |-
if(cycle == "lifetime", (price / formula.duration.months).toFixed(2),
number((price/(formula.cycleDays)*31) + (if (shared, formula.sharedAdjustment,0))).toFixed(2)
)
priceInFuture: if(formula.willRenew && startDate < now(),formula.pricePerMonth,number(0).toFixed(2))
willRenew: |-
if(cycle == "lifetime", 'lifetime',
endDate == null || (endDate.relative() > now()+cycle)
)
totalCost: |-
if(cycle == "lifetime", price.toFixed(2),
if(startDate > now(),number(0).toFixed(2),(formula.cyclesStarted * number(price)).toFixed(2))
)
durationPrecise: formula.duration.months.toFixed(2)
endDateOrForever: if (endDate, endDate, date('2099-01-01'))
cycleDaysRounded: duration(number(cycle).ceil().toString()+cycle.slice(-1))
cyclesPassed: if(cycle == "lifetime", formula.cyclesStarted+'d', formula.cyclesStarted+(cycle.slice(-1)))
properties:
formula.enabled:
displayName: active
formula.priceAdjusted:
displayName: priceAdjusted
formula.nextPaymentDate:
displayName: nextPaymentDate
formula.started:
displayName: started
formula.cycleDays:
displayName: cycleDays
formula.priceInFuture:
displayName: priceThisMonth
views:
- type: table
name: Subscriptions
groupBy:
property: formula.enabled
direction: DESC
order:
- formula.icon
- file.name
- product
- formula.status
- formula.nextPaymentDate
- cycle
- price
- formula.pricePerMonth
- formula.priceInFuture
- formula.totalCost
- currency
- formula.started
- formula.cyclesPassed
- startDate
- endDate
- platform
- formula.duration
- formula.durationPrecise
- tags
- account
- account-holder
- category
- share-price
- notes
sort:
- property: formula.nextPaymentDate
direction: ASC
- property: cycle
direction: ASC
- property: file.name
direction: ASC
summaries:
price: Sum
formula.pricePerMonth: Total
formula.priceInFuture: Total
formula.totalCost: Total
columnSize:
formula.icon: 38
file.name: 204
note.product: 129
formula.status: 128
formula.nextPaymentDate: 106
note.cycle: 62
note.price: 62
formula.pricePerMonth: 61
formula.priceInFuture: 63
formula.totalCost: 65
note.currency: 55
formula.cyclesPassed: 41
note.endDate: 126
formula.durationPrecise: 62
note.tags: 128
note.account: 172
note.account-holder: 72
note.category: 112
note.share-price: 67
note.notes: 204
- type: table
name: Subscriptions Active
filters:
and:
- formula.enabled == true
order:
- formula.icon
- file.name
- formula.status
- formula.nextPaymentDate
- cycle
- price
- formula.pricePerMonth
- currency
- formula.started
- endDate
- formula.duration
- account
- account-holder
- category
- tags
- shared
- share-price
- formula.priceAdjusted
- notes
sort:
- property: formula.nextPaymentDate
direction: ASC
- property: file.name
direction: ASC
columnSize:
formula.icon: 38
formula.status: 128
formula.nextPaymentDate: 116
note.cycle: 47
formula.pricePerMonth: 58
note.currency: 55
note.endDate: 126
formula.durationPrecise: 254
note.account: 172
note.account-holder: 53
note.category: 112
formula.priceAdjusted: 80
note.notes: 204
- type: table
name: Subscriptions Inactive
filters:
and:
- formula.enabled == false
order:
- formula.icon
- file.name
- endDate
- cycle
- price
- formula.pricePerMonth
- currency
- formula.started
- formula.duration
- account
- account-holder
- category
- tags
- shared
- share-price
- formula.priceAdjusted
- notes
sort:
- property: endDate
direction: DESC
- property: formula.started
direction: ASC
columnSize:
formula.icon: 38
formula.status: 128
formula.nextPaymentDate: 116
note.cycle: 47
formula.pricePerMonth: 58
note.currency: 55
note.endDate: 126
formula.durationPrecise: 254
note.account: 172
note.account-holder: 53
note.category: 112
formula.priceAdjusted: 80
note.notes: 204
- type: calendar
name: Renewals
filters:
and:
- formula.enabled == true
- formula.isRenewing == true
startDate: formula.nextPaymentDate
showICS_ics_q3765di1smf12p46b: false
showICS_ics_0k7qvgafnmghaso1i: false
- type: calendar
name: Ending
filters:
and:
- formula.isRenewing == false
startDate: formula.nextPaymentDate
- type: table
name: Subscriptions Soon
filters:
and:
- formula.enabled == true
order:
- formula.icon
- file.name
- formula.status
- formula.nextPaymentDate
- notes
sort:
- property: formula.nextPaymentDate
direction: ASC
limit: 4
columnSize:
formula.icon: 38
formula.status: 128
formula.nextPaymentDate: 116
note.currency: 55
note.cycle: 66
note.endDate: 126
note.account: 172
note.account-holder: 53
note.category: 112
formula.priceAdjusted: 80
note.notes: 204
- type: list
name: Subscriptions Soon List
filters:
and:
- formula.enabled == true
order:
- formula.icon
- file.name
- formula.status
- notes
- formula.nextPaymentDate
- price
sort:
- property: formula.nextPaymentDate
direction: ASC
limit: 3
columnSize:
formula.icon: 38
formula.status: 128
formula.nextPaymentDate: 116
note.currency: 55
note.cycle: 66
note.endDate: 126
note.account: 172
note.account-holder: 53
note.category: 112
formula.priceAdjusted: 80
note.notes: 204
separator: " "
markers: number
nestedProperties: false
indentProperties: false
- type: calendar
name: Opened Calendar
order:
- file.name
startDate: note.startDate
endDate: formula.endDateOrForever
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment