forked from intro-skipper/intro-skipper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidate-and-update-manifest.js
167 lines (140 loc) · 5.18 KB
/
validate-and-update-manifest.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
const https = require('https');
const crypto = require('crypto');
const fs = require('fs');
const { URL } = require('url');
const repository = process.env.GITHUB_REPOSITORY;
const version = process.env.VERSION;
const targetAbi = "10.9.11.0";
// Read manifest.json
const manifestPath = './manifest.json';
if (!fs.existsSync(manifestPath)) {
console.error('manifest.json file not found');
process.exit(1);
}
// Read README.md
const readmePath = './README.md';
if (!fs.existsSync(readmePath)) {
console.error('README.md file not found');
process.exit(1);
}
const jsonData = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const newVersion = {
version,
changelog: `- See the full changelog at [GitHub](https://github.com/${repository}/releases/tag/10.9/v${version})\n`,
targetAbi,
sourceUrl: `https://github.com/${repository}/releases/download/10.9/v${version}/intro-skipper-v${version}.zip`,
checksum: getMD5FromFile(),
timestamp: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z')
};
async function updateManifest() {
await validVersion(newVersion);
// Add the new version to the manifest
jsonData[0].versions.unshift(newVersion);
console.log('Manifest updated successfully.');
updateReadMeVersion();
cleanUpOldReleases();
// Write the modified JSON data back to the file
fs.writeFileSync(manifestPath, JSON.stringify(jsonData, null, 4), 'utf8');
process.exit(0); // Exit with no error
}
async function validVersion(version) {
console.log(`Validating version ${version.version}...`);
const isValidChecksum = await verifyChecksum(version.sourceUrl, version.checksum);
if (!isValidChecksum) {
console.error(`Checksum mismatch for URL: ${version.sourceUrl}`);
process.exit(1); // Exit with an error code
} else {
console.log(`Version ${version.version} is valid.`);
}
}
async function verifyChecksum(url, expectedChecksum) {
try {
const hash = await downloadAndHashFile(url);
return hash === expectedChecksum;
} catch (error) {
console.error(`Error verifying checksum for URL: ${url}`, error);
return false;
}
}
async function downloadAndHashFile(url, redirects = 5) {
if (redirects === 0) {
throw new Error('Too many redirects');
}
return new Promise((resolve, reject) => {
https.get(url, (response) => {
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
// Follow redirect
const redirectUrl = new URL(response.headers.location, url).toString();
downloadAndHashFile(redirectUrl, redirects - 1)
.then(resolve)
.catch(reject);
} else if (response.statusCode === 200) {
const hash = crypto.createHash('md5');
response.pipe(hash);
response.on('end', () => {
resolve(hash.digest('hex'));
});
response.on('error', (err) => {
reject(err);
});
} else {
reject(new Error(`Failed to get '${url}' (${response.statusCode})`));
}
}).on('error', (err) => {
reject(err);
});
});
}
function getMD5FromFile() {
const fileBuffer = fs.readFileSync(`intro-skipper-v${version}.zip`);
return crypto.createHash('md5').update(fileBuffer).digest('hex');
}
function getReadMeVersion() {
let parts = targetAbi.split('.').map(Number);
parts.pop();
return parts.join(".");
}
function updateReadMeVersion() {
const newVersion = getReadMeVersion();
const readMeContent = fs.readFileSync(readmePath, 'utf8');
const updatedContent = readMeContent
.replace(/Jellyfin.*\(or newer\)/, `Jellyfin ${newVersion} (or newer)`)
if (readMeContent != updatedContent) {
fs.writeFileSync(readmePath, updatedContent);
console.log('Updated README with new Jellyfin version.');
} else {
console.log('README has already newest Jellyfin version.');
}
}
function cleanUpOldReleases() {
// Extract all unique targetAbi values
const abiSet = new Set();
jsonData.forEach(entry => {
entry.versions.forEach(version => {
abiSet.add(version.targetAbi);
});
});
// Convert the Set to an array and sort it in descending order
const abiArray = Array.from(abiSet).sort((a, b) => {
const aParts = a.split('.').map(Number);
const bParts = b.split('.').map(Number);
for (let i = 0; i < aParts.length; i++) {
if (aParts[i] > bParts[i]) return -1;
if (aParts[i] < bParts[i]) return 1;
}
return 0;
});
// Identify the highest and second highest targetAbi
const highestAbi = abiArray[0];
const secondHighestAbi = abiArray[1];
// Filter the versions array to keep only those with the highest or second highest targetAbi
jsonData.forEach(entry => {
entry.versions = entry.versions.filter(version =>
version.targetAbi === highestAbi || version.targetAbi === secondHighestAbi
);
});
}
async function run() {
await updateManifest();
}
run();