Skip to content

Commit 79ac124

Browse files
authored
Merge pull request JetBrains#3770 from JetBrains/ktl-1118-news-collector-script
KTL-1118 Main page revamp: latest news collector script
2 parents d9db542 + 6e58596 commit 79ac124

7 files changed

+138
-0
lines changed
Loading
Loading

Diff for: latest-news/Featured_1280x720-5.png

546 KB
Loading

Diff for: latest-news/compose-featured_blog_1280x720-2.png

271 KB
Loading

Diff for: latest-news/latest-news.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[
2+
{
3+
"title": "Kotlin News: KotlinConf 2024 Tickets, Compose Multiplatform 1.5.0, Grants Program Winners, and More",
4+
"date": "August 30, 2023",
5+
"link": "https://blog.jetbrains.com/kotlin/2023/08/kotlin-news-jul-aug-23/",
6+
"image": "latest-news/Featured_1280x720-5.png",
7+
"description": "In this new edition of the Kotlin digest, we’re bringing you the most exciting news and updates from July and August. KotlinConf 2024 tickets are now available! KotlinConf is bringing the Kotlin community together for the fifth time on May 22–24, 2024, at the Bella Center in Copenhagen, Denmark! There will be workshops, talks, networking […]"
8+
},
9+
{
10+
"title": "Compose Multiplatform 1.5.0 Release",
11+
"date": "August 28, 2023",
12+
"link": "https://blog.jetbrains.com/kotlin/2023/08/compose-multiplatform-1-5-0-release/",
13+
"image": "latest-news/compose-featured_blog_1280x720-2.png",
14+
"description": "As of today, Compose Multiplatform 1.5.0 is available for you to use. It takes the Jetpack Compose declarative UI framework for Kotlin and extends it beyond Android to desktop, iOS, and web. The desktop version is stable, iOS is in Alpha, and support for web is experimental. For a full introduction, see the Compose Multiplatform […]"
15+
},
16+
{
17+
"title": "Win a Trip to KotlinConf’24 in the Kotlin Multiplatform Contest!",
18+
"date": "August 25, 2023",
19+
"link": "https://blog.jetbrains.com/kotlin/2023/08/kotlin-multiplatform-contest-2024/",
20+
"image": "latest-news/DSGN-17108-Kotlin-Multiplatform-contest-banners-3_Blog-Featured-image-1280x600-copy.png",
21+
"description": "Are you a student or recent graduate? Have you already tried building projects with Kotlin Multiplatform, a trending technology that lets you build apps for Android, iOS, desktop, web, and server while sharing Kotlin code between all the platforms? If so, don’t miss this opportunity to practice your multiplatform coding skills by taking part in […]"
22+
},
23+
{
24+
"title": "Exposed moving forward",
25+
"date": "August 4, 2023",
26+
"link": "https://blog.jetbrains.com/kotlin/2023/08/exposed-moving-forward/",
27+
"image": "latest-news/DSGN-17089-Exposed-moving-forward_Blog-Featured-image-1280x600-copy.png",
28+
"description": "Exposed started out a few years back at JetBrains, as a lightweight ORM/DAO written in Kotlin. It has since been used internally on a number of critical products at JetBrains, and despite being classified as a Team project on GitHub, it has garnered a large number of external users.  While the main person on the […]"
29+
}
30+
]

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"eslint": "8.14.0",
8585
"eslint-config-next": "12.1.6",
8686
"eslint-config-prettier": "8.5.0",
87+
"fast-xml-parser": "4.2.7",
8788
"next": "^13.4.15",
8889
"next-compose-plugins": "^2.2.1",
8990
"next-global-css": "^1.3.1",

Diff for: scripts/latest-news/index.js

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
const https = require('https');
2+
const fs = require('fs');
3+
const path = require('path');
4+
const { XMLParser } = require('fast-xml-parser');
5+
6+
const projectRoot = process.cwd();
7+
const LATEST_NEWS_FOLDER_NAME = 'latest-news';
8+
const NEWS_DATA = 'latest-news.json';
9+
10+
const latestNewsDirectory = path.join(projectRoot, LATEST_NEWS_FOLDER_NAME);
11+
12+
if (!fs.existsSync(latestNewsDirectory)) {
13+
fs.mkdirSync(latestNewsDirectory);
14+
}
15+
16+
getLatestNews();
17+
18+
async function getLatestNews() {
19+
const latestNewsXMl = await getLatestNewsXML();
20+
21+
const parser = new XMLParser({
22+
ignoreDeclaration: true
23+
});
24+
const allJson = parser.parse(latestNewsXMl);
25+
const items = allJson['rss']['channel']['item'];
26+
const latestNews = [];
27+
28+
for (const item of items.splice(0, 4)) {
29+
const imagePath = await saveImage(item.featuredImage);
30+
latestNews.push({
31+
title: item.title,
32+
date: item.pubDate,
33+
link: item.link,
34+
image: imagePath,
35+
description: item.description
36+
})
37+
}
38+
39+
fs.writeFileSync(path.join(latestNewsDirectory, NEWS_DATA), JSON.stringify(latestNews), 'utf8');
40+
}
41+
42+
async function getLatestNewsXML() {
43+
return await doRequest({
44+
hostname: 'blog.jetbrains.com',
45+
port: 443,
46+
path: '/kotlin/feed/',
47+
method: 'GET'
48+
});
49+
}
50+
51+
async function saveImage(imageUrl) {
52+
const url = new URL(imageUrl);
53+
54+
const localFileName = imageUrl.split('/').pop();
55+
const localFilePath = path.join(latestNewsDirectory, localFileName);
56+
const relativePath = path.relative(projectRoot, localFilePath);
57+
58+
const fileStream = fs.createWriteStream(localFilePath);
59+
60+
return new Promise((resolve, reject) => {
61+
const request = https.get(url, (response) => {
62+
if (response.statusCode !== 200) {
63+
reject(new Error(`Failed to download image. HTTP status code: ${response.statusCode}`));
64+
return;
65+
}
66+
67+
response.pipe(fileStream);
68+
69+
fileStream.on('finish', () => {
70+
fileStream.close();
71+
resolve(relativePath);
72+
});
73+
74+
fileStream.on('error', (err) => {
75+
reject(err);
76+
});
77+
});
78+
79+
request.on('error', reject);
80+
81+
request.end();
82+
});
83+
}
84+
85+
86+
function doRequest(options) {
87+
return new Promise((resolve, reject) => {
88+
const req = https.request(options, (res) => {
89+
res.setEncoding('utf8');
90+
let responseBody = '';
91+
92+
res.on('data', (chunk) => {
93+
responseBody += chunk;
94+
});
95+
96+
res.on('end', () => {
97+
resolve(responseBody);
98+
});
99+
});
100+
101+
req.on('error', (err) => {
102+
reject(err);
103+
});
104+
105+
req.end();
106+
});
107+
}

0 commit comments

Comments
 (0)