@krx3d/tizentube2 1.30.40 → 1.30.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@krx3d/tizentube2",
3
3
  "appName": "TizenTube",
4
- "version": "1.30.40",
4
+ "version": "1.30.60",
5
5
  "description": "TizenTube is an ad-free and sponsor-free solution for your favourite streaming website on your Tizen (Samsung) TVs.",
6
6
  "packageType": "mods",
7
7
  "websiteURL": "https://youtube.com/tv?additionalDataUrl=http%3A%2F%2Flocalhost%3A8085%2Fdial%2Fapps%2FYouTube",
@@ -0,0 +1,180 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Removes old @krx3d/tizentube2 versions from npm.
4
+
5
+ .DESCRIPTION
6
+ The publish workflow attempts this on every run and cannot succeed. npm
7
+ removed legacy tokens in November 2025, so a granular access token is the only
8
+ kind left, and since August 2026 one with bypass-2FA is refused for sensitive
9
+ actions — unpublish among them. CI has no way to answer a 2FA challenge, so
10
+ removal has to happen from a machine where someone can type a code.
11
+
12
+ This does that, with the guard rails the workflow learned the hard way:
13
+
14
+ - the version npm's `latest` tag points at is never touched, nor is any
15
+ other dist-tag target
16
+ - nothing is removed without showing the list and asking first
17
+ - one 2FA code covers the whole batch, since npm accepts --otp per command
18
+ and a code stays valid for its whole window
19
+
20
+ npm only allows unpublishing a version within 72 hours of its publication, so
21
+ anything older is listed and skipped rather than attempted. Those stay on the
22
+ registry as deprecated versions, which is all the workflow can do to them.
23
+
24
+ .PARAMETER Package
25
+ The npm package name. Defaults to this repo's package.
26
+
27
+ .PARAMETER Keep
28
+ Extra versions to leave alone, on top of every dist-tag target.
29
+
30
+ .PARAMETER IncludeOlder
31
+ Also attempt versions outside npm's 72-hour window. npm usually refuses
32
+ these, but a refused request changes nothing, so it costs only the
33
+ attempt — and it does sometimes go through for a package nothing depends
34
+ on. Off by default so the normal run stays quiet.
35
+
36
+ .PARAMETER WhatIf
37
+ List what would be removed and stop.
38
+
39
+ .EXAMPLE
40
+ .\unpublish-old-versions.ps1 -WhatIf
41
+
42
+ .EXAMPLE
43
+ .\unpublish-old-versions.ps1 -Keep 1.30.40
44
+ #>
45
+ param(
46
+ [string]$Package = '@krx3d/tizentube2',
47
+ [string[]]$Keep = @(),
48
+ [int]$WindowHours = 72,
49
+ [switch]$IncludeOlder,
50
+ [switch]$WhatIf
51
+ )
52
+
53
+ $ErrorActionPreference = 'Stop'
54
+
55
+ function Get-Packument {
56
+ param([string]$Name)
57
+ # Read the registry directly. `npm view` has its own HTTP cache, and a stale
58
+ # answer here means acting on a version list that is no longer true.
59
+ $url = "https://registry.npmjs.org/$Name"
60
+ try {
61
+ return Invoke-RestMethod -Uri $url -Method Get -Headers @{ Accept = 'application/json' }
62
+ } catch {
63
+ throw "Could not read $url : $($_.Exception.Message)"
64
+ }
65
+ }
66
+
67
+ Write-Host "Reading the registry for $Package ..."
68
+ $doc = Get-Packument -Name $Package
69
+
70
+ $live = @($doc.versions.PSObject.Properties.Name)
71
+ if (-not $live -or $live.Count -eq 0) { throw "No live versions found for $Package." }
72
+
73
+ # Every dist-tag target is protected, not just latest: installing a tag npm
74
+ # hands out must keep working.
75
+ $tagTargets = @($doc.'dist-tags'.PSObject.Properties | ForEach-Object { $_.Value })
76
+ $protected = @($tagTargets + $Keep) | Where-Object { $_ } | Sort-Object -Unique
77
+
78
+ Write-Host ""
79
+ Write-Host "Live versions: $($live.Count)"
80
+ Write-Host "Protected: $($protected -join ', ')"
81
+ Write-Host ""
82
+
83
+ $now = [DateTime]::UtcNow
84
+ $removable = @()
85
+ $tooOld = @()
86
+
87
+ foreach ($v in $live) {
88
+ if ($protected -contains $v) { continue }
89
+ $stamp = $doc.time.PSObject.Properties[$v]
90
+ if (-not $stamp) { $tooOld += $v; continue }
91
+ # Invoke-RestMethod converts an ISO timestamp into a DateTime on its own,
92
+ # but only sometimes — and re-parsing the result fails outright under a
93
+ # non-US culture, where it renders as MM/dd/yyyy and Parse then rejects it.
94
+ # So take a DateTime as-is and parse a string as invariant UTC.
95
+ $raw = $stamp.Value
96
+ if ($raw -is [DateTime]) {
97
+ $published = $raw.ToUniversalTime()
98
+ } else {
99
+ $styles = [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal
100
+ $published = [DateTime]::Parse([string]$raw, [System.Globalization.CultureInfo]::InvariantCulture, $styles)
101
+ }
102
+ $age = ($now - $published).TotalHours
103
+ if ($age -le $WindowHours) {
104
+ $removable += [pscustomobject]@{ Version = $v; AgeHours = [math]::Round($age, 1) }
105
+ } elseif ($IncludeOlder) {
106
+ $removable += [pscustomobject]@{ Version = $v; AgeHours = [math]::Round($age, 1) }
107
+ } else {
108
+ $tooOld += $v
109
+ }
110
+ }
111
+
112
+ if ($tooOld.Count -gt 0) {
113
+ Write-Host "Outside npm's $WindowHours-hour window, so they cannot be removed ($($tooOld.Count)):" -ForegroundColor DarkGray
114
+ Write-Host " $($tooOld -join ', ')" -ForegroundColor DarkGray
115
+ Write-Host " Pass -IncludeOlder to attempt them anyway." -ForegroundColor DarkGray
116
+ Write-Host ""
117
+ }
118
+
119
+ if ($removable.Count -eq 0) {
120
+ Write-Host "Nothing to remove." -ForegroundColor Green
121
+ return
122
+ }
123
+
124
+ if ($IncludeOlder) {
125
+ Write-Host "To attempt ($($removable.Count)), including versions npm will probably refuse:" -ForegroundColor Yellow
126
+ } else {
127
+ Write-Host "Can be removed ($($removable.Count)):" -ForegroundColor Yellow
128
+ }
129
+ $removable | Format-Table -AutoSize | Out-String | Write-Host
130
+
131
+ if ($WhatIf) {
132
+ Write-Host "-WhatIf given, so nothing was changed." -ForegroundColor Cyan
133
+ return
134
+ }
135
+
136
+ $answer = Read-Host "Remove these $($removable.Count) versions from npm? (type 'yes')"
137
+ if ($answer -ne 'yes') {
138
+ Write-Host "Cancelled; nothing was changed." -ForegroundColor Cyan
139
+ return
140
+ }
141
+
142
+ # One code for the batch. npm accepts --otp on each command and the code stays
143
+ # valid for its window, so this asks once rather than once per version.
144
+ $otp = Read-Host "Two-factor code from your authenticator"
145
+ if (-not $otp) {
146
+ Write-Host "No code given; nothing was changed." -ForegroundColor Cyan
147
+ return
148
+ }
149
+
150
+ $removed = 0
151
+ $failed = @()
152
+
153
+ foreach ($item in $removable) {
154
+ $spec = "$Package@$($item.Version)"
155
+ Write-Host ""
156
+ Write-Host "Unpublishing $spec ..."
157
+ $output = & npm unpublish $spec --otp $otp 2>&1
158
+ if ($LASTEXITCODE -eq 0) {
159
+ $removed++
160
+ Write-Host " removed" -ForegroundColor Green
161
+ } else {
162
+ $failed += $item.Version
163
+ Write-Host ($output | Out-String).Trim() -ForegroundColor Red
164
+ if (($output | Out-String) -match 'one-time pass|EOTP|invalid otp') {
165
+ # A stale code fails every remaining version the same way; stop and let
166
+ # the next run start from a fresh one rather than burning through the list.
167
+ Write-Host ""
168
+ Write-Host "The code was rejected. Run this again with a fresh one." -ForegroundColor Yellow
169
+ break
170
+ }
171
+ }
172
+ }
173
+
174
+ Write-Host ""
175
+ Write-Host "Removed $removed of $($removable.Count)."
176
+ if ($failed.Count -gt 0) {
177
+ Write-Host "Still present: $($failed -join ', ')" -ForegroundColor Yellow
178
+ }
179
+ Write-Host "A removed version number can never be published again, so the next" -ForegroundColor DarkGray
180
+ Write-Host "build continues from where the bump left off." -ForegroundColor DarkGray