LogoMultiPost

发布内容原理

发布函数

src/components/Sync 文件夹中,有对应不同平台的发布组件,例如 DynamicTabArticleTabVideoTab 等。

它们在组织好发布所需的信息,即 SyncData 类型的数据后,会调用 src/options/index.tsx 文件中的 funcPublish 函数来进行标签页的创建和脚本的注入。

const funcPublish = async (data: SyncData) => {
  // 如果平台数组不为空,则创建标签页
  if (Array.isArray(data.platforms) && data.platforms.length > 0) {
    // 创建标签页
    createTabsForPlatforms(data)
      .then(async (tabs) => {
        // 注入脚本
        injectScriptsToTabs(tabs, data);
 
        // 通知标签页管理器新建了新的标签页
        // 这里会触发 `src/background/services/tabs.ts` 文件中的 `tabsManagerMessageHandler` 函数
        chrome.runtime.sendMessage({
          type: 'MUTLIPOST_EXTENSION_TABS_MANAGER_REQUEST_ADD_TABS',
          data: data,
          tabs: tabs,
        });
 
        // 依次激活标签页,以便注入的脚本可以正常工作
        for (const [tab] of tabs) {
          if (tab.id) {
            await chrome.tabs.update(tab.id, { active: true });
            await new Promise((resolve) => setTimeout(resolve, 2000));
          }
        }
      })
      .catch((error) => {
        console.error('Error creating tabs or groups:', error);
      });
  } else {
    console.error('No valid platforms specified');
  }
};

创建标签页

在上一节,我们看到 funcPublish 函数会调用 createTabsForPlatforms 函数来创建标签页,并在之后调用 injectScriptsToTabs 函数来注入脚本。这两个函数在 src/sync/common.ts 文件中。

它的原理是使用了 chrome.tabschrome.scripting 的 API 来创建标签页和注入脚本。

// 平台信息映射,因为定义的类型比较多,所以拆分成了多个文件 article.ts、dynamic.ts、video.ts
export const infoMap: Record<string, PlatformInfo> = {
  ...DynamicInfoMap,
  ...ArticleInfoMap,
  ...VideoInfoMap,
};
 
// 获取平台信息
export function getDefaultPlatformInfo(platform: string): PlatformInfo | null {
  return infoMap[platform] || null;
}
 
// 创建标签页
export async function createTabsForPlatforms(data: SyncData) {
  const tabs = [];
  // 从 SyncData 中获取需要发布的平台
  for (const platform of data.platforms) {
    // 获取平台信息
    const info = getDefaultPlatformInfo(platform);
    if (info) {
      // 创建标签页
      const tab = await chrome.tabs.create({ url: info.injectUrl });
      // 将标签页和平台信息推入数组
      tabs.push([tab, platform]);
    }
  }
 
  // 创建标签页组
  const groupId = await chrome.tabs.group({ tabIds: tabs.map((t) => t[0].id!) });
  const group = await chrome.tabGroups.get(groupId);
 
  // 更新标签页组的标题和颜色
  await chrome.tabGroups.update(group.id, {
    color: 'blue',
    title: `MultiPost-${new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })}`,
  });
 
  return tabs;
}

注入脚本

injectScriptsToTabs 函数中,我们为每个标签页添加了监听器,当标签页加载完成后,会调用 getDefaultPlatformInfo 函数来获取平台信息,并注入脚本。

// 注入脚本
export async function injectScriptsToTabs(tabs: [chrome.tabs.Tab, string][], data: SyncData) {
  // 遍历标签页
  for (const t of tabs) {
    // 获取标签页和平台信息
    const tab = t[0];
    const platform = t[1];
    // 如果标签页 ID 存在,则添加监听器
    if (tab.id) {
      // 添加监听器
      chrome.tabs.onUpdated.addListener(function listener(tabId, info) {
        // 如果标签页 ID 和平台信息匹配,则注入脚本
        if (tabId === tab.id && info.status === 'complete') {
          // 移除监听器
          chrome.tabs.onUpdated.removeListener(listener);
          // 获取平台信息
          const info = getDefaultPlatformInfo(platform);
          // 如果平台信息存在,则注入脚本
          if (info) {
            // 注入脚本
            chrome.scripting.executeScript({
              target: { tabId: tab.id },
              func: info.injectFunction,
              args: [data],
            });
          }
        }
      });
    }
  }
}

On this page