Nextcloud Memories修改地图路径教程

-
-
2025-12-01

摘要

本文提供了一种hack方式,用于自定义Nextcloud Memories app中地图页面的tile server。实现效果如下:

图中的地图图源已经从原本的OpenStreetMap(OSM)被替换成了天地图。

Memories App介绍

MemoriesNextcloud的一个应用,可以在应用商店直接安装。其主要功能是可以用多种方式(时间线、文件夹、专辑、人物、地图等)展示Nextcloud中存储的照片。因为采取了不同的索引方式,所以,其对大量的图片表现极佳

Memories Map更换tile server

Map是Memories的一个功能,可以根据照片EXIF中存储的GPS信息,把照片标记在地图上。这是一个很棒的功能。但是,其使用的地图是OSM。如果特定地区访问OSM有困难,用户可能会希望替换加载地图的tile server。遗憾的是,memories官方并没有提供修改途径,任何现有的资源也没有找到解决办法。本文提供了一种hack方式,用于自定义tile server。

基本的思路是,虽然官方没有提供自定义方法,但这是一个web服务,不涉及编译到二进制文件,所以我们总是可以通过替换源文件url的方式来实现。

在什么地方修改

可以在Memories源码中搜索“.openstreetmap.”,发现只有4个文件包含了相关链接。涉及到tile server的主要有两个。

lib/Controller/PageController.php

        $policy->addAllowedConnectDomain('data:');
        
        // Allow OSM
        $policy->addAllowedFrameDomain('www.openstreetmap.org');
        $addImageDomain('https://tile.openstreetmap.org');
        $addImageDomain('https://*.a.ssl.fastly.net');
        
        $policy->addAllowedConnectDomain('nominatim.openstreetmap.org');

src/components/top-matter/MapSplitMatter.vue

import 'leaflet/dist/leaflet.css';
import 'leaflet-edgebuffer';

const OSM_TILE_URL = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
const OSM_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors';

// CSS transition time for zooming in/out cluster animation

第二个文件MapSplitMatter.vue中出现的是tile server的地址;第一个文件中出现的是相关的安全策略,允许特定域名的跨域请求。

如何修改

下方以把openstreetmap图源替换为arcgisonline为例。关于该选择什么地图源,见文章最下方的讨论。

注意:因为要修改源码,所以在修改前,推荐对原文件进行备份,避免操作失误导致插件失效。

更改tile server地址

Vue项目编译后,原本的MapSplitMatter.vue会产生两个文件,都要进行替换:

/var/www/html/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js/var/www/html/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js.map中的'https://tile.openstreetmap.org/{z}/{x}/{y}.png'替换成'https://server.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}.png'

示例命令如下:

# 替换 .js 文件
sed -i 's|https://tile.openstreetmap.org/{z}/{x}/{y}.png|https://server.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}.png|g' memories-components_top-matter_MapSplitMatter_vue.js

# 替换 .js.map 文件
sed -i 's|https://tile.openstreetmap.org/{z}/{x}/{y}.png|https://server.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}.png|g' memories-components_top-matter_MapSplitMatter_vue.js.map

也可以在交互式编辑器中手动进行替换。

更改安全策略

/var/www/html/custom_apps/memories/lib/Controller/PageController.php中如下位置(约91行)

        // Allow OSM
       $policy->addAllowedFrameDomain('www.openstreetmap.org');
       $addImageDomain('https://tile.openstreetmap.org');
       $addImageDomain('https://*.a.ssl.fastly.net');

添加$addImageDomain('https://server.arcgisonline.com');

更改service worker

仅进行上述两项修改,在memories map界面,按F12打开开发者工具,右键浏览器左上角刷新图标,选择”清空缓存并硬性重新加载“,可以看到新的地图源被正确的加载了进来。

但是别高兴的太早!当你重新点击刷新后,会发现又回到了旧的地图源。通过一些排查,我发现这是一个缓存问题。浏览器试图在使用旧版本的MapSplitMatter_vue.js。一开始,我以为和我的nginx设置有关,后来发现这个问题来自于service worker。

Service worker是现代web应用起核心作用的浏览器技术,可以实现一些离线优先的体验和高级缓存策略。找到service_worker.js/var/www/html/custom_apps/memories/js/memories-service-worker.js),发现里面有一个很长的缓存列表(源文件是单行,这里为了阅读体验,进行了格式化):

const ie = [
    ...
    {
        'revision': '71e436917cb50dff6a23a7fbff4a2b70',
        'url': '/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js.map?v=446bfb0d6731968034b0'
    }, {
        'revision': null,
        'url': '/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js?v=446bfb0d6731968034b0'
    },
    ...
];

通过修改revision字段,破坏缓存:

const ie = [
    ...
    {
        'revision': 'hacked_by_me_1_' + Date.now(),
        'url': '/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js.map?v=446bfb0d6731968034b0'
    }, {
        'revision': 'hacked_by_me_2_' + Date.now(),
        'url': '/custom_apps/memories/js/memories-components_top-matter_MapSplitMatter_vue.js?v=446bfb0d6731968034b0'
    },
    ...
];

注意:Date.now()生成的时间戳会随每次修改变化,若多次修改可能导致缓存混乱。更稳妥的方式是修改revision为固定自定义字符串。

问题解决!

我该选取什么地图源

如果你的图片在原本的OpenStreetMap上显示是正常的,说明照片 EXIF 中的 GPS 信息(WGS84 坐标系,EPSG:4326)可被 OSM 兼容,替换的 tile server 需支持 EPSG:3857 投影坐标系(即OSM 采用的 Web 墨卡托投影)。

上面的教程中,是以arcgisonline为例。这个图源的zoom level只能到13级,继续放大后会显示”Map data not yet available“。

还可以选择天地图,图源免费使用,且国内加载极快。但是需要注册并申请密钥,且矢量图层和注解图层需要分别请求,导致需要修改更多的代码(本文不做介绍,但欢迎讨论)。仅按照本文方法进行修改,最终可以正常加载矢量街道图层,但因为没有注解图层,所以没有街道名显示。

如果大家有更多国内可访问的EPSG:3857地图源推荐,欢迎在评论区讨论。

在测试地图源的过程中,推荐大家使用开源软件QGIS,用于快速验证tile server的坐标系,最大zoom level,加载速度等等。

一些说明

本文方法的局限

本文方法的核心内容是对url进行替换,在memories应用升级后,所有更改的文件会被还原。届时需要重新替换。可以考虑写脚本进行替换。

环境

Nextcloud:Nextcloud Hub 10 (31.0.10),Docker Compose安装。

Memories:7.7.0 (git hash: 5ebd498)


目录