mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 05:42:22 +00:00
fix(news): list Local newest first
Local ranked its reports by severity first. A country's own news now carries no severity, so in a conflict area GDELT's reports (severity 1 and up) could crowd every one of its stories out of the 40 listed. Local is now newest first; severity still shows by colour. Also: readTitle reads Conflicts headlines only, the economy category's comment and the attribution popover name World News API's category, and KNOWN-ISSUES names Core's ids for World News API's categories.
This commit is contained in:
1 parent
82057cbb51
commit
427463cc45
7 files changed
+21
-19
No files matched your search
@@ -5850,7 +5850,7 @@ request viewbox and continues searching without that geographic preference.
|
||||
### News (November 2026)
|
||||
|
||||
- **What it shows.** Events ▸ **News**: the last 24 hours only, or the fewer hours a server names. Zoomed out, one beacon per hotspot with its count for the window and its trend, and a breathing beacon per developing situation (still under reduced motion). Below 2,500 km (7,500 km with a hotspot chosen), the hotspot outlines with disputed areas dotted and named, and every placed report as a ground-clamped marker: fill is severity (0 grey no physical event, 1 yellow minor, 2 orange significant, 3 red major), the icon is the category, the rim is attestation (solid confirmed, dashed claim, thin single), size grows with sources and the marker fades over the day. Colour never marks a side. Up to ten picture cards (physical events with two or more sources, major or pressing) stand over their markers without overlapping. A selected report's card reads "Source: host ↗" and opens the article.
|
||||
- **Panel.** The right-rail NEWS panel (`src/ui/newsPanel.js`, `src/ui/news/`) has a time window at the top (the server's 24 h, or 12, 6, 3 or 1 h; the hotspot counts are read for the chosen window) and two sections. **Conflicts**: hotspot chips with counts, a severity floor (significant and above by default), a category filter, the chosen event, and a continuous feed, newest first. **Local**, while the camera is below 3,000 km: every report in the area at the view centre, named at the top ("News from …") and outlined on the globe, which then shows those reports instead of the hotspots' news; at sea, reports within 500 km. A disputed area of the bundled list (11, see `src/data/local_data/natural_earth/README.md`), or a territory Natural Earth gives no country code (Somaliland, Northern Cyprus and others), is named as itself and read from no country's outlets; elsewhere Natural Earth's default country lines apply. Each card shows the publisher's picture when the event has one (hotlinked, no referrer, publisher credited), the headline (a model's English headline marked as such), a mono meta line (severity marker, category, place, sources, age), who reported it, attestation and media chips, and the service it came through ("via GDELT Project"). Open, a card plays the post's clip on request. A click flies the camera straight down from 150 km and selects the report.
|
||||
- **Panel.** The right-rail NEWS panel (`src/ui/newsPanel.js`, `src/ui/news/`) has a time window at the top (the server's 24 h, or 12, 6, 3 or 1 h; the hotspot counts are read for the chosen window) and two sections. **Conflicts**: hotspot chips with counts, a severity floor (significant and above by default), a category filter, the chosen event, and a continuous feed, newest first. **Local**, while the camera is below 3,000 km: every report in the area at the view centre, newest first, named at the top ("News from …") and outlined on the globe, which then shows those reports instead of the hotspots' news; at sea, reports within 500 km. A disputed area of the bundled list (11, see `src/data/local_data/natural_earth/README.md`), or a territory Natural Earth gives no country code (Somaliland, Northern Cyprus and others), is named as itself and read from no country's outlets; elsewhere Natural Earth's default country lines apply. Each card shows the publisher's picture when the event has one (hotlinked, no referrer, publisher credited), the headline (a model's English headline marked as such), a mono meta line (severity marker, category, place, sources, age), who reported it, attestation and media chips, and the service it came through ("via GDELT Project"). Open, a card plays the post's clip on request. A click flies the camera straight down from 150 km and selects the report.
|
||||
- **Notices.** A section whose key the server lacks says "{provider} key required" and names the variable; a refused key says "{provider} refused its key"; a spent daily allowance says "{provider} limit reached for today". The other section keeps working.
|
||||
- **Source.** `sources.news` (`createNewsSource`, export `./layers/news/source`) reads same-origin `/api/news/*` with a 15 s timeout, a 4 MiB cap and record-by-record validation; `newsQueryAllowed` lets a host admit exactly the client's requests. Core's local server (`server/providers/news.js`) forwards only those GET requests to `GEV_NEWS_ORIGIN` when it is set.
|
||||
- **Built-in backend.** With `GEV_NEWS_ORIGIN` unset, Core answers the same routes itself (`server/providers/news/keyed.js`). **Conflicts** needs no key: the last 24 h of GDELT 2.0 event exports (15-minute files on `data.gdeltproject.org`, about 100 KB each), physical violence only (CAMEO roots 18–20), one report per story with copies of one agency story merged, placed at GDELT's location for it (a town the article's words name beats a bare country). Titles are the article's page title from GDELT's GKG export of the same quarter hour (about 6 MB each) for the newest 3 h, else the words of the article's address; GDELT's actor coding is never shown. With `LIVEUAMAP_API_KEY`, Liveuamap's mapped items stand beside GDELT's. **Local** reads World News API (`WORLDNEWSAPI_KEY`) by the source country at the view centre, once per country every 30 minutes (about 1.5 points a read, at most `WORLDNEWSAPI_DAILY_READS` reads a day, default 30), plus the Conflicts reports placed inside the area. A country's own stories keep World News API's category (politics, business, else other) and no severity: the rules read fighting and crises, and everyday headlines mislead them. Areas come from the bundled Natural Earth countries and disputed areas (`server/providers/news/areas.js`). Conflicts' categories, relevance and severity are bundled rules (`categorize.js`); a news server may replace them.
|
||||
|
||||
@@ -142,9 +142,9 @@ Status: Open (limits)
|
||||
Natural Earth's default country lines apply, so a place in Western Sahara,
|
||||
for example, is named with the country those lines put it in. GDELT places a whole city at one point: Jerusalem's falls
|
||||
inside East Jerusalem, so it is named "Jerusalem" alone.
|
||||
- A country's own stories in Local keep World News API's category (political,
|
||||
economy, else other) and carry no severity; fighting there shows through the
|
||||
Conflicts reports placed in the area.
|
||||
- A country's own stories in Local keep World News API's category (politics as
|
||||
political, business as economy, else other) and carry no severity; fighting
|
||||
there shows through the Conflicts reports placed in the area.
|
||||
- Local needs a World News API key. Its free plan allows 50 points a day; Core
|
||||
stops at `WORLDNEWSAPI_DAILY_READS` reads (default 30) and Local then says the
|
||||
daily limit is reached.
|
||||
|
||||
@@ -29,7 +29,7 @@ export const CATEGORY_ORDER = Object.freeze([
|
||||
'disaster',
|
||||
'protest',
|
||||
'political',
|
||||
// Rules only, for the Local section's national news.
|
||||
// Business and trade: the rules' reading, or World News API's business.
|
||||
'economy',
|
||||
]);
|
||||
|
||||
|
||||
@@ -103,13 +103,18 @@ const WORLD_NEWS_CATEGORY = { politics: 'political', business: 'economy' };
|
||||
const list = (value) =>
|
||||
value ? new Set(value.split(',').filter(Boolean)) : null;
|
||||
|
||||
/** The rules' reading of a headline: category, relevance and severity. */
|
||||
function readTitle(title, { dedicated }) {
|
||||
/** The rules' reading of a Conflicts headline: category, relevance, severity. */
|
||||
function readTitle(title) {
|
||||
const read = categorizeText({ title });
|
||||
const { category } = read;
|
||||
return {
|
||||
category,
|
||||
relevance: relevanceOf({ category, tags: read.tags, title, dedicated }),
|
||||
relevance: relevanceOf({
|
||||
category,
|
||||
tags: read.tags,
|
||||
title,
|
||||
dedicated: true,
|
||||
}),
|
||||
severity: severityByRules({ category, tags: read.tags, title }),
|
||||
};
|
||||
}
|
||||
@@ -146,7 +151,7 @@ export function liveuamapReport(item) {
|
||||
kind: 'liveuamap',
|
||||
side: 'unknown',
|
||||
// A conflict map: everything it posts is at least related.
|
||||
...readTitle(item.title, { dedicated: true }),
|
||||
...readTitle(item.title),
|
||||
severityBy: 'rules',
|
||||
publishedAt: item.publishedAt,
|
||||
geo: {
|
||||
|
||||
@@ -498,7 +498,7 @@ export const DATA_CREDITS = [
|
||||
'News: every report is credited to its own publisher and links to the original article; ' +
|
||||
'pictures are the publishers’ own, shown from their sites with the publisher named. ' +
|
||||
'Places, categories, severity and English headlines are derived automatically, by ' +
|
||||
'bundled rules or by the configured news server, and can be wrong.',
|
||||
'bundled rules, the news provider or the configured news server, and can be wrong.',
|
||||
},
|
||||
{
|
||||
// GDELT's terms ask for a citation and a link.
|
||||
|
||||
@@ -762,9 +762,10 @@ export function inPolygons(polygons, point) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The reports near `centre` that pass the filters, most severe and newest
|
||||
* first: any pin inside `area` (outline polygons), or without one within
|
||||
* NEWS_IN_VIEW_RADIUS_KM.
|
||||
* The reports near `centre` that pass the filters, newest first: any pin
|
||||
* inside `area` (outline polygons), or without one within
|
||||
* NEWS_IN_VIEW_RADIUS_KM. Newest, not most severe: an area's own news often
|
||||
* carries no severity, and the area's fighting would otherwise crowd it out.
|
||||
*/
|
||||
export function reportsInView(
|
||||
reports,
|
||||
@@ -786,10 +787,6 @@ export function reportsInView(
|
||||
(filters.category === 'all' || r.category === filters.category) &&
|
||||
r.pins?.some(near),
|
||||
)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
reportSeverity(b) - reportSeverity(a) ||
|
||||
b.publishedAt.localeCompare(a.publishedAt),
|
||||
)
|
||||
.sort((a, b) => b.publishedAt.localeCompare(a.publishedAt))
|
||||
.slice(0, limit);
|
||||
}
|
||||
@@ -672,7 +672,7 @@ test('in view: half-degree cells and reports within 500 km of the centre', () =>
|
||||
reportsInView([near, far, old, major], centre, filters, NOW).map(
|
||||
(r) => r.id,
|
||||
),
|
||||
['major', 'near'],
|
||||
['near', 'major'],
|
||||
);
|
||||
assert.deepEqual(reportsInView([near], null, filters, NOW), []);
|
||||
assert.deepEqual(reportsInView([], centre, filters, NOW), []);
|
||||
|
||||
Reference in new issue
Block a user