לדלג לתוכן

משתמש:מוטי בוט/עדכון קטגוריה.js

מתוך המכלול, האנציקלופדיה היהודית

לתשומת ליבך: לאחר הפרסום, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.

  • פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
  • גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
  • אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
//הקוד הראשוני נכתב ע"י משתמש גאון הירדן שופץ ושוכתב על ידי
/**
 * Creates a button that, when clicked, prompts the user to confirm whether they want to update a category.
 * If the user confirms, the `upAll` function is called.
 */
mw.loader
  .using([
    "mediawiki.api",
    "mediawiki.util",
    "mediawiki.ForeignApi",
    "ext.gadget.mw-import",
  ])
  .done(function () {
    if (mw.config.get("wgNamespaceNumber") !== 14) {
      return;
    }

    const api = new mw.Api();
    const wiki = new mw.ForeignApi(mw.user.options.get("userjs-import-source") === "direct" ? "https://he.wikipedia.org/w/api.php" : "/import/get_wik1i.php", {
      anonymous: true,
    });
    const Import = new mw.import(mw.user.options.get("userjs-import-source") === "direct" ? "https://he.wikipedia.org/w/api.php" : "https://import.hamichlol.org.il/");

    let isPaused = false;
    let isRunning = false;
    let currentState = null;

    function createButton() {
      const button = mw.util.addPortletLink(
        "p-views",
        "#",
        "עדכון כל הקטגוריה",
        "updateCategory",
        null,
        null,
        "#ca-history"
      );

      $(button).click(() => {
        console.log("Clicked the button! isPaused: " + isPaused);

        if (!isRunning) {
          console.log("Starting new update!");
          isRunning = true;
          updateAllPags();
          $(button).find("a").text("השהה עדכון");
        } else {
          console.log("Toggling update state!");
          isPaused = !isPaused;
          if (!isPaused) updateAllPags(currentState);
          $(button)
            .find("a")
            .text(isPaused ? "המשך עדכון" : "השהה עדכון");
        }
      });
    }

    async function updateAllPags(state = null) {
      if (!state) {
        const localMap = await memberList("local");
        const wikiMap = await memberList("wikipedia");
        state = {
          localMap,
          wikiMap,
          localTitles: Object.keys(localMap),
          index: 0,
          stage: "localMap",
        };
      }

      let { localMap, wikiMap, localTitles, index, stage } = state;

      if (stage === "localMap") {
        while (index < localTitles.length) {
          if (isPaused) {
            currentState = { localMap, wikiMap, localTitles, index, stage };
            return;
          }

          const title = localTitles[index];
          index++;
          const isWiki = wikiMap[title];
          const isUpdate = compareTimestamps(
            localMap[title]?.revisions[0]?.timestamp,
            wikiMap[title]?.revisions[0]?.timestamp || 0
          );

          const lastRevision = localMap[title].revisions[0];
          const filter =
            !/יבוא|עי?דכון|יובאה/.test(lastRevision.comment) ||
            /תמונה|תוכן/.test(lastRevision.comment) ||
            lastRevision.comment.includes("nowiki") ||
            lastRevision.tags.some(
              (tag) => tag === "הסרת תמונה" || tag === "הסרת תוכן"
            );

          if (isWiki && !isUpdate) {
            delete localMap[title];
            delete wikiMap[title];
            continue;
          }
          if (filter) {
            console.warn(`${title} עבר עריכה מקומית!`, lastRevision);
            delete localMap[title];
            if (isWiki) delete wikiMap[title];
            continue;
          }
          try {
            const { text, summary } = await Import.importWikitext({
              page: title,
              exist: true,
            });
            await editTemplate(title, text, summary);
          } catch {}
          delete localMap[title];
          if (isWiki) delete wikiMap[title];
        }
        stage = "wikiMap";
        index = 0;
      }
      console.log("localMapLength", Object.keys(localMap).length);
      console.log("wikiMapLength", Object.keys(wikiMap).length);

      if (stage === "wikiMap") {
        for (const member in wikiMap) {
          if (isPaused) {
            currentState = { localMap, wikiMap, index: 0, stage };
            return;
          }
          mw.notify(`מייבא ${member}...`);
          try {
            const shouldUpdate = await confirmUpdate(member);
            if (shouldUpdate === false) continue;
            const { text, summary } = await Import.importWikitext({
              page: member,
              exist: shouldUpdate,
            });
            await editTemplate(member, text, summary);
          } catch (error) {
            console.error(error);
          }
        }
      }

      // Reset when finished
      currentState = null;
      isPaused = false;
      $("#updateCategory").find("a").text("עדכון חוזר");
    }

    /**
     * Retrieves a list of members from a specified category on either the local wiki or an external wiki.
     * @param {string} targetApi - A string indicating the API to use. It can be either "local" for the local wiki or "wikipedia" for an external wiki. The default value is "w".
     * @param {Array} members - An array to store the fetched members. The default value is an empty array.
     * @param {string} gcmcontinue - A string representing the continue parameter for pagination. The default value is `null`.
     * @returns {Promise<Array>} - An array of member objects representing the members of the specified category.
     */
    async function memberList(targetApi) {
      const category = mw.config.get("wgPageName");
      const members = {};
      let gcmcontinue = null;

      const parameters = {
        prop: "revisions",
        generator: "categorymembers",
        utf8: 1,
        rvprop: "timestamp",
        gcmtitle: category,
        gcmnamespace: "10",
        gcmlimit: "max",
      };

      if (targetApi === "local") {
        parameters.rvprop = "timestamp|comment|tags";
      }

      const apiGet = targetApi === "wikipedia" ? wiki : api;

      while (true) {
        if (gcmcontinue) {
          parameters.gcmcontinue = gcmcontinue;
        }

        try {
          const response = await apiGet.get(parameters);
          Object.keys(response.query.pages).forEach((id) => {
            members[response.query.pages[id].title] = response.query.pages[id];
          });
          console.log(response);
          console.log(Object.keys(members).length);

          if (response.continue) {
            gcmcontinue = response.continue.gcmcontinue;
          } else {
            break;
          }
        } catch (error) {
          console.error("Error fetching members:", error);
          break;
        }
      }

      return members;
    }

    function compareTimestamps(localtimestamp, wikitimestamp) {
      const localDate = Date.parse(localtimestamp);
      const wikiDate = Date.parse(wikitimestamp);
      // Rest of the code
      return localDate < wikiDate;
    }
    /**
     * Makes an API call to edit a wiki page with the provided title, wikitext, and summary.
     * @param {string} title - The title of the wiki page to be edited.
     * @param {string} wikitext - The content of the wiki page to be edited.
     * @param {string} summary - The summary of the edit.
     * @returns {Promise<void>}
     */
    async function editTemplate(title, wikitext, summary) {
      try {
        const { edit } = await api.postWithEditToken({
          action: "edit",
          format: "json",
          bot: true,
          title,
          text: wikitext,
          summary,
          tags: "auto-update",
        });
        if (edit) {
          console.log(title, edit);
          if (edit?.new === "") mw.notify(`תבנית ${title} יובאה`);
        }
      } catch (error) {
        console.error(`Error editing ${title}:`, error);
      }
    }
    async function confirmUpdate(member) {
      const windowManager = new OO.ui.WindowManager();
      $("body").append(windowManager.$element);

      const messageDialog = new OO.ui.MessageDialog();
      windowManager.addWindows([messageDialog]);

      const linkElement = $("<a>", {
        href: `/${member}`,
        text: member,
      });

      // בדיקת קיום הדף
      let pageExists = false;
      try {
        const result = await api.get({
          titles: member,
          formatversion: 2,
        });
        pageExists = !result.query.pages[0].missing ;
        linkElement.addClass(!pageExists ? "new" : "");
      } catch (error) {
        console.error("Error checking page existence:", error);
      }

      const message = $("<p>").append("האם ברצונך לעדכן ", linkElement);

      const config = {
        message: message,
        actions: [
          { action: "accept", label: "כן", flags: ["primary", "progressive"] },
          { action: "reject", label: "לא", flags: "safe" },
        ],
      };

      const result = await windowManager.openWindow(messageDialog, config)
        .closed;
      windowManager.$element.remove(); // ניקוי ה-DOM לאחר השימוש

      if (!result || result.action === "reject") {
        return false;
      } else if (result.action === "accept") {
        return !pageExists ? 0 : 1;
      }
    }

    mw.user.getRights((r) => {
      if (r.includes("bot")) createButton();
    });
  });