Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ jobs:
fwrite(STDERR, "Missing CamName at index {$index}.\n");
exit(1);
}

$legacy = $camera["Address"]["legacy"] ?? null;
if (!is_array($legacy)) {
fwrite(STDERR, "Missing Address.legacy at index {$index}.\n");
exit(1);
}

$province = $legacy["province"]["name"] ?? "";
if ($province === "") {
fwrite(STDERR, "Missing legacy province at index {$index}.\n");
exit(1);
}

$location = $camera["Location"] ?? null;
if (!is_array($location) || !array_key_exists("lat", $location) || !array_key_exists("lng", $location)) {
fwrite(STDERR, "Missing Location structure at index {$index}.\n");
exit(1);
}
}
echo "Validated " . count($data) . " unique cameras.\n";
'
Expand Down
89 changes: 89 additions & 0 deletions .github/workflows/vietmap-addresses.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Enrich VietMap addresses

on:
workflow_dispatch:
inputs:
limit:
description: "Maximum cameras to process (0 = all missing)"
required: false
default: "0"
force:
description: "Re-enrich cameras that already have VietMap data"
required: false
type: boolean
default: false
schedule:
- cron: "17 20 * * 1"

permissions:
contents: write
pull-requests: write

jobs:
enrich:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v5
with:
ref: main
fetch-depth: 0

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
coverage: none

- name: Enrich camera addresses
env:
VIETMAP_API_KEY: ${{ secrets.VIETMAP_API_KEY }}
INPUT_LIMIT: ${{ github.event.inputs.limit || '0' }}
INPUT_FORCE: ${{ github.event.inputs.force || 'false' }}
run: |
if [ -z "$VIETMAP_API_KEY" ]; then
echo "::error::Missing repository secret VIETMAP_API_KEY"
exit 1
fi

ARGS=(--limit="$INPUT_LIMIT")
if [ "$INPUT_FORCE" = "true" ]; then
ARGS+=(--force)
fi

php scripts/enrich-vietmap.php "${ARGS[@]}"

- name: Validate enriched data
run: |
php -r '
$data = json_decode(file_get_contents("data-camera.json"), true, 512, JSON_THROW_ON_ERROR);
foreach ($data as $i => $camera) {
if (!isset($camera["Address"]["legacy"]["province"]["name"])) {
fwrite(STDERR, "Camera {$i} has invalid legacy address structure.\n");
exit(1);
}
}
'

- name: Create update pull request
env:
GH_TOKEN: ${{ github.token }}
run: |
if git diff --quiet -- data-camera.json; then
echo "No address changes."
exit 0
fi

BRANCH="automation/vietmap-addresses-${GITHUB_RUN_ID}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
git add data-camera.json
git commit -m "data: enrich camera addresses from VietMap"
git push origin "$BRANCH"

gh pr create \
--base main \
--head "$BRANCH" \
--title "data: enrich camera addresses from VietMap" \
--body "Automated VietMap v4 enrichment. Stores structured legacy/current addresses and coordinates; UI filters by the legacy district only."
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

- Hiển thị camera theo dạng dashboard responsive cho desktop và mobile.
- Tìm kiếm theo tên đường, giao lộ hoặc khu vực.
- Lọc theo quận/khu vực.
- Lọc theo quận/huyện cũ từ dữ liệu địa chỉ có cấu trúc.
- Tùy chọn 6–24 camera mỗi trang.
- Tự làm mới theo chu kỳ 5/10/15/30 giây hoặc tắt hoàn toàn.
- Làm mới từng camera hoặc toàn bộ camera đang hiển thị.
Expand Down Expand Up @@ -34,7 +34,8 @@ Mở <http://localhost:8000>.
## Cấu trúc chính

- `index.html`: giao diện và logic hiển thị camera.
- `data-camera.json`: danh sách camera.
- `data-camera.json`: danh sách camera, tọa độ và địa chỉ cũ/mới có cấu trúc.
- `scripts/enrich-vietmap.php`: enrich địa chỉ bằng VietMap v4 (`display_type=6`), lưu legacy + current và tọa độ.
- `proxy.php`: proxy ảnh camera từ nguồn giao thông TP.HCM.
- `composer.json`: dependency PHP.

Expand Down Expand Up @@ -74,3 +75,16 @@ The project exposes crawlable resources in addition to the JavaScript camera dir
- `manifest.webmanifest` and `favicon.svg` — app/site identity metadata.

The homepage and detail pages include canonical URLs, social metadata and Schema.org JSON-LD.


## Enrich địa chỉ bằng VietMap

Thiết lập biến môi trường `VIETMAP_API_KEY`, sau đó chạy:

```bash
VIETMAP_API_KEY=... php scripts/enrich-vietmap.php
```

Script dùng tên camera/giao lộ và quận cũ hiện có để tìm trên VietMap Geocode v4 với `display_type=6`.
Kết quả cũ được lưu vào `Address.legacy`, kết quả sau sáp nhập vào `Address.current`, còn tọa độ từ Place v4 được lưu ở `Location`.
UI chỉ filter theo `Address.legacy.district`; không gọi VietMap khi người dùng mở trang.
24 changes: 20 additions & 4 deletions camera.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,22 @@ function h(string $value): string
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function cameraLegacyAddress(array $camera): array
{
$legacy = $camera['Address']['legacy'] ?? [];
return is_array($legacy) ? $legacy : [];
}

function cameraDistrict(array $camera): string
{
return trim((string) ($camera['Disctrict'] ?? $camera['District'] ?? 'TP.HCM'));
$legacy = cameraLegacyAddress($camera);
return trim((string) ($legacy['district']['name'] ?? 'TP.HCM'));
}

function cameraFullAddress(array $camera): string
{
$legacy = cameraLegacyAddress($camera);
return trim((string) ($legacy['full'] ?? ''));
}

$cameraId = isset($_GET['id']) ? trim((string) $_GET['id']) : '';
Expand Down Expand Up @@ -55,8 +68,10 @@ function cameraDistrict(array $camera): string
} else {
$cameraName = trim((string) $camera['CamName']);
$district = cameraDistrict($camera);
$fullAddress = cameraFullAddress($camera);
$pageTitle = 'Camera ' . $cameraName . ' – ' . $district . ' | TP.HCM';
$pageDescription = 'Xem camera giao thông ' . $cameraName . ' tại ' . $district . ', TP.HCM. Hình ảnh camera được cập nhật tự động để tiện theo dõi tình hình giao thông.';
$locationDescription = $fullAddress !== '' ? $fullAddress : $district . ', TP.HCM';
$pageDescription = 'Xem camera giao thông ' . $cameraName . ' tại ' . $locationDescription . '. Hình ảnh camera được cập nhật tự động để tiện theo dõi tình hình giao thông.';
$canonical = BASE_URL . '/camera.php?id=' . rawurlencode($cameraId);
$imageUrl = BASE_URL . '/proxy.php?id=' . rawurlencode($cameraId);

Expand Down Expand Up @@ -86,8 +101,9 @@ function cameraDistrict(array $camera): string
'name' => $cameraName,
'address' => [
'@type' => 'PostalAddress',
'addressLocality' => 'Hồ Chí Minh',
'addressRegion' => $district,
'streetAddress' => cameraFullAddress($camera) ?: $cameraName,
'addressLocality' => $district,
'addressRegion' => 'Hồ Chí Minh',
'addressCountry' => 'VN',
],
],
Expand Down
Loading
Loading