Skip to content

Commit 87ab157

Browse files
committed
Refacto
1 parent c19429d commit 87ab157

4 files changed

Lines changed: 99 additions & 104 deletions

File tree

.github/workflows/update.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Update RSS
1+
name: update-rss-feed
22

33
on:
44
schedule:
@@ -29,7 +29,7 @@ jobs:
2929
- name: Check if debug files exist
3030
id: debug_check
3131
run: |
32-
if [[ -f debug.html || -f screenshot.png ]]; then
32+
if [[ -f debug.html || -f debug.png ]]; then
3333
echo "found=true" >> $GITHUB_OUTPUT
3434
else
3535
echo "found=false" >> $GITHUB_OUTPUT
@@ -42,7 +42,7 @@ jobs:
4242
name: debug-artifacts
4343
path: |
4444
debug.html
45-
screenshot.png
45+
debug.png
4646
4747
- name: Commit RSS update
4848
run: |
File renamed without changes.

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
# Google DPC RSS feed
2-
3-
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/MisterJack49/dpc-version-rss/update.yml?label=Feed%20update)
1+
# Google Android DPC versions RSS feed
42

3+
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/MisterJack49/dpc-version-rss/update.yml?label=RSS%20update&logo=github&logoColor=white) ![Static Badge](https://img.shields.io/badge/RSS-Link-FFA500?logo=rss&logoColor=%23FFA500)
54

65
This generates a rss feed from the latest versions of the [Google Android DPC](https://play.google.com/store/apps/details?id=com.google.android.apps.work.clouddpc&hl=en_GB) listed on [APKPure](https://apkpure.com/android-device-policy/com.google.android.apps.work.clouddpc/versions) for the available history.
76

8-
The feed is updated once a day at 00:00 GMT via a Github Action and get published [here](https://misterjack49.github.io/dpc-version-rss/).
7+
The feed is updated once a day at 00:00 GMT via a Github Action and get published to Github Pages.
98

10-
You can subscribe to this feed to monitor the release of new Google Android DPC versions.
119

index.js

Lines changed: 93 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@ import puppeteer from 'puppeteer-extra';
22
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
33
import {create} from 'xmlbuilder2';
44
import {XMLParser} from 'fast-xml-parser';
5-
import fs from 'fs';
5+
import fs from 'fs/promises';
66
import {executablePath} from "puppeteer";
77

88
const puppeteerStealth = StealthPlugin();
99
puppeteerStealth.enabledEvasions.delete('user-agent-override');
1010
puppeteer.use(puppeteerStealth);
1111

12+
const xmlPath = 'docs/index.xml';
13+
const URL = 'https://apkpure.com/android-device-policy/com.google.android.apps.work.clouddpc/versions';
14+
1215
(async () => {
1316
console.log('🛫 - Launching browser...');
17+
1418
const browser = await puppeteer.launch({
1519
executablePath: executablePath(),
1620
readTimeout: 5 * 60 * 1000,
@@ -21,129 +25,122 @@ puppeteer.use(puppeteerStealth);
2125
'--disable-dev-shm-usage',
2226
],
2327
});
24-
console.log('✔️ - Browser launched');
28+
console.log('🤖 - Browser launched');
2529

26-
let versions = [];
2730
const page = await browser.newPage();
28-
try {
29-
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36')
31+
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36')
3032

31-
const URL = 'https://apkpure.com/android-device-policy/com.google.android.apps.work.clouddpc/versions';
33+
try {
34+
console.log('🌐 - Loading page...');
35+
await page.goto(URL, {waitUntil: 'domcontentloaded'});
3236

33-
await page.goto(URL, { waitUntil: 'domcontentloaded' });
34-
3537
console.log('✔️ - Page loaded');
3638

3739
await page.waitForFunction(() => {
3840
return !document.querySelector('form#challenge-form, .cf-browser-verification') &&
3941
!/Attention Required/.test(document.title);
40-
}, { timeout: 20000 }).catch(() => {
42+
}, {timeout: 20000}).catch(() => {
4143
throw new Error('⛔ - Cloudflare challenge did not resolve in time');
4244
});
43-
44-
versions = await page.evaluate(() => {
45-
const items = document.querySelectorAll('li a.ver_download_link');
46-
const result = [];
47-
48-
items.forEach(link => {
49-
const versionDiv = link.querySelector('.ver-item-n');
50-
const dateSpan = link.querySelector('.update-on');
51-
52-
const version = versionDiv ? versionDiv.textContent.trim().replace(/^Android Device Policy\s*/i, '').replace(/\s+/g, ' ') : null;
53-
const date = dateSpan ? dateSpan.textContent.trim() : null;
54-
const href = link.getAttribute('href');
55-
56-
if (version && date && href) {
57-
result.push({
58-
version,
59-
date,
60-
link: href.startsWith('http') ? href : `https://apkpure.com${href}`
61-
});
62-
}
63-
});
6445

65-
return result;
46+
const versions = await page.evaluate(() => {
47+
return Array.from(document.querySelectorAll('li a.ver_download_link'))
48+
.map(link => {
49+
const version = link.querySelector('.ver-item-n')?.textContent
50+
?.trim()
51+
?.replace(/^Android Device Policy\s*/i, '')
52+
?.replace(/\s+/g, ' ');
53+
54+
const date = link.querySelector('.update-on')?.textContent.trim();
55+
const href = link.getAttribute('href');
56+
57+
return version && date && href
58+
? {version, date, link: href.startsWith('http') ? href : `https://apkpure.com${href}`}
59+
: null;
60+
})
61+
.filter(Boolean);
6662
});
6763

6864
if (!versions || versions.length === 0) {
6965
console.warn('⚠️ - No versions scraped — dumping page content for debugging');
7066

71-
const fs = await import('fs/promises');
7267
const html = await page.content();
73-
await fs.mkdir('docs', { recursive: true });
68+
await fs.mkdir('docs', {recursive: true});
7469
await fs.writeFile('debug.html', html);
75-
await page.screenshot({ path: 'screenshot.png', fullPage: true });
70+
await page.screenshot({path: 'debug.png', fullPage: true});
7671

7772
console.log('📝 - Saved debug.html and screenshot.png to docs/');
78-
process.exit(0);
73+
return;
7974
}
80-
81-
if (versions.length) console.log(`🦝 - Scraped ${versions.length} versions`);
82-
} catch (e) {
83-
console.error('🏴‍☠️ - Page load failed:', e);
84-
const errorHtml = await page.content();
85-
await page.screenshot({ path: 'screenshot.png', fullPage: true });
8675

87-
const fs = await import('fs/promises');
88-
await fs.mkdir('docs', { recursive: true });
89-
await fs.writeFile('docs/debug.html', errorHtml);
76+
if (versions.length) console.log(`🦝 - Scraped ${versions.length} versions`);
9077

91-
console.log('📝 - Saved debug.html and screenshot.png to docs/');
92-
}
78+
await browser.close();
9379

94-
await browser.close();
95-
96-
//console.log(versions);
80+
let existingItems = [];
9781

98-
let existingItems = [];
99-
const xmlPath = 'docs/index.xml'
82+
if ((await fs.stat(xmlPath)).isFile()) {
83+
const xmlData = await fs.readFile(xmlPath, 'utf-8');
84+
const parser = new XMLParser();
85+
const parsed = parser.parse(xmlData);
86+
const items = parsed?.rss?.channel?.item || [];
87+
existingItems = Array.isArray(items) ? items : [items];
88+
}
10089

101-
if (fs.existsSync(xmlPath)) {
102-
const xmlData = fs.readFileSync(xmlPath, 'utf-8');
103-
const parser = new XMLParser();
104-
const parsed = parser.parse(xmlData);
105-
const items = parsed?.rss?.channel?.item || [];
106-
existingItems = Array.isArray(items) ? items : [items];
107-
}
90+
// Use a Set for fast version-date matching
91+
const existingKeys = new Set(existingItems.map(i => `${i.guid}`));
92+
93+
// Add only new entries
94+
const newItems = versions
95+
.filter(v => !existingKeys.has(v.version))
96+
.map(v => {
97+
const pubDate = new Date().toUTCString();
98+
const guid = v.version;
99+
return {
100+
title: `Android Device Policy ${v.version} - ${v.date}`,
101+
link: v.link,
102+
description: `Version ${v.version} released on ${v.date}`,
103+
pubDate,
104+
guid
105+
};
106+
})
107+
108+
console.log(`🔎 - Found ${newItems.length} new versions`);
109+
110+
if(newItems.length === 0){
111+
return
112+
}
108113

109-
// Use a Set for fast version-date matching
110-
const existingKeys = new Set(
111-
existingItems.map(i => `${i.guid}`)
112-
);
113-
114-
// Add only new entries
115-
const newItems = versions
116-
.filter(v => !existingKeys.has(v.version))
117-
.map(v => {
118-
const pubDate = new Date().toUTCString();
119-
const guid = v.version;
120-
return {
121-
title: `Android Device Policy ${v.version} - ${v.date}`,
122-
link: v.link,
123-
description: `Version ${v.version} released on ${v.date}`,
124-
pubDate,
125-
guid
126-
};
127-
})
128-
.filter(item => !existingKeys.has(item.title));
129-
130-
console.log(`🔎 - Found ${newItems.length} new versions`);
131-
132-
// Combine and sort
133-
const allItems = [...newItems, ...existingItems].slice(0, 50); // keep only latest 50
134-
135-
const rss = {
136-
rss: {
137-
'@version': '2.0',
138-
channel: {
139-
title: 'Android Device Policy Versions',
140-
link: 'https://apkpure.com/android-device-policy/com.google.android.apps.work.clouddpc/versions',
141-
description: 'Tracks version updates on APKPure',
142-
item: allItems
114+
// Combine and sort
115+
const allItems = [...newItems, ...existingItems].slice(0, 50); // keep only latest 50
116+
117+
const rss = {
118+
rss: {
119+
'@version': '2.0',
120+
channel: {
121+
title: 'Android Device Policy Versions',
122+
link: 'https://apkpure.com/android-device-policy/com.google.android.apps.work.clouddpc/versions',
123+
description: 'Tracks version updates on APKPure',
124+
item: allItems
125+
}
143126
}
144-
}
145-
};
127+
};
128+
129+
console.log(`📝 - Saving xml feed...`)
130+
const xml = create({version: '1.0', encoding: 'UTF-8'}, rss).end({prettyPrint: true});
131+
await fs.writeFile(xmlPath, xml);
132+
console.log(`💾 - Saving done`)
133+
} catch (err) {
134+
console.error('💥 Scraper failed:', err);
135+
136+
const errorHtml = await page.content();
137+
await page.screenshot({path: 'debud.png', fullPage: true});
146138

147-
const xml = create({version: '1.0', encoding: 'UTF-8'}, rss).end({prettyPrint: true});
148-
fs.writeFileSync(xmlPath, xml);
139+
await fs.mkdir('docs', {recursive: true});
140+
await fs.writeFile('debug.html', errorHtml);
141+
142+
console.log('📝 - Saved debug.html and debug.png to docs/');
143+
} finally {
144+
await browser.close();
145+
}
149146
})();

0 commit comments

Comments
 (0)