iOS版のTampermonkeyが登場したので出退勤時のタイムカード打刻(ジョブカン)を自動化してみたよ!というお話

最近、Redditを眺めていたところ、「iOS版Tampermonkeyが登場した」という話題が目に留まりました。
Tampermonkeyとは、Webサイト上でUserScript(ユーザースクリプト)を実行するためのWebブラウザ拡張機能で、操作の自動化や画面のカスタマイズを行うことができる、ユーザーのブラウジング体験を向上させる強力なツールです。
そんなTampermonkeyが、ついにiOSの標準ブラウザであるSafariの機能拡張として対応したということで、個人的に以前から煩わしく感じていた会社の出退勤打刻作業の半自動化に挑戦してみました。

iOS版Tampermonkey

UserScriptを実行できるブラウザはAppStoreには以前から存在していましたが、肝心のUserScript機能を使用するにはサブスプリクションに課金をしなければならなかったり、使い勝手の面でも標準のSafariに劣っていました。特にSafariが機能拡張に対応してからは、広告除去機能やジェスチャー操作などユーザーが欲しい機能を組み込む事ができ圧倒的優位になっていました。今回登場したiOS版のTampermonkeyは買い切り型で、購入後の毎月課金が必要無いということもあり、わざわざ他の専用ブラウザを使う必要がなくなり、iPhoneのSafariだけでスクリプトが動作するという環境が整ったわけです。

出退勤打刻の自動化フロー

私の勤務先では、通常はPC版ジョブカンを使って出退勤の打刻を行い、外出先へ直行する場合などには、モバイル版を使ってGPS位置情報を付加して打刻する運用になっています。

前提ツール:OmniFocus + iOSショートカット

私は日々のタスク管理にOmniFocusを利用しており、始業前のルーティンの中に「ジョブカン打刻」のタスクを設定しています。このタスクのメモ欄にURLを仕込み、iOSショートカットと連携することで、自動化の流れを構築しています。
PC版のTampermonkeyでも流用できますが、あくまでもiPhoneで使う事を目的としています。

ジョブカン打刻の自動化の流れ

私が運用している自動化の流れは以下のようになっています。

  1. OmniFocusのタスク(ジョブカン打刻)から、iOSショートカットを使ってジョブカンのログインページへジャンプ。
  2. Tampermonkeyスクリプトが自動でログインを実行。
  3. ログイン後、打刻ページに遷移。
  4. 打刻ボタンはあえて手動で押す(後述の理由あり)。
  5. 打刻ページの勤務状況の表示に応じて自動的にアプリをOmniFocusに戻す・ブラウザではジョブカンからYahoo!へ移動する処理を実行する。

打刻は敢えて手動にしている

ログインから打刻ページへの遷移は自動で行えるのですが、打刻ボタン押す処理だけは手動操作にしています。
というのも、うっかりジョブカンにアクセスしただけで打刻処理がされてしまうと、

  • 実際には出社していないのに「出勤」になってしまう。
  • まだ退勤していないのに「退勤」処理されてしまう。

といった誤打刻のリスクがあるためです。これを防ぐために、敢えて打刻処理だけは自分で確認・操作するようにしています。

OmniFocusとの連携でタスクも自動完了

さらに便利なのが、ショートカットを経由してジョブカンにアクセスしていることによって、打刻作業が終わるとOmniFocus側のタスクも完了扱いになる点です。これにより、日々のルーティンがスムーズに進みます。

実際のPC版自動化

PC版はログインした時点で打刻ページへ移管するので、自動ログインをすることと、手動で打刻ボタンを押した後の画面上の勤務状況を認識して、OmniFocusへ戻り、ブラウザをYahoo!のトップページへ移動する処理を自動化しています。
ただし、OmniFocus・Yahoo!への移管については時間によって処理が別れてきます。

時間ごとの挙動
  • 勤務時間前で未出勤の表示 → 移管しない(出勤時の打刻を想定)
  • 勤務時間内で未出勤の表示 → 移管しない(遅刻を想定)
  • 勤務時間内で勤務中の表示 → 移管する(出勤後を想定)
  • 勤務時間後で勤務中の表示 → 移管しない(退勤時の打刻を想定)
  • 勤務時間後で退出中の表示 → 移管する(退勤後を想定)

私の例では8:30~17:30の間を勤務時間とし、勤務時間の前後を境にしての勤務状況の表示に基づいて処理を分けています。

実際のモバイル版自動化

モバイル版はログインした時点では打刻ページへ移管しないので、ジョブカンへアクセス後に自動ログイン処理を行い、打刻ページへ移動する部分を自動化しています。
さらに、モバイル版では打刻ボタンを押す部分も自動化しています。なぜなら、モバイル版はこの後に位置情報を取得するボタンを押して、更に、打刻の最終確認がある為です。位置情報を取得するボタンと最終確認を手動処理にすることによって誤打刻を回避する事ができると想定しています。
打刻後の処理については勤務状況表示が多少違っていますが、おおむねPC版と同じ状況で処理を分けています。

今回作成したコード

// ==UserScript==
// @name         ジョブカン完全自動化スクリプト
// @namespace    https://jobcan.jp/
// @version      1.2
// @description  ログイン→打刻→OmniFocus→Yahooまで全自動対応。PC・スマホ両対応です!
// @author       GeekNote
// @match        https://ssl.jobcan.jp/login/*
// @match        https://ssl.jobcan.jp/m/index/index
// @match        https://ssl.jobcan.jp/m/work/accessrecord?_m=adit
// @match        https://ssl.jobcan.jp/m/work/stampcomplete/*
// @match        https://id.jobcan.jp/users/*
// @match        https://ssl.jobcan.jp/employee*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    const email = "メールアドレスまたはスタッフコード";
    const password = "パスワード";
    const clientId = "勤怠会社ID";
    const url = location.href;
    // ------------------------------------------------------
    // 共通: OmniFocus実行後にYahooへリダイレクト(location方式)
    // ------------------------------------------------------
    function launchOmniFocusAndRedirect() {
        const omniURL = "omnifocus://"; // ← 修正済み
        window.location = omniURL;
        setTimeout(() => {
            window.location.href = "https://yahoo.co.jp";
        }, 1500);
    }
    // ① スマートフォン: ログイン自動化
    if (url.startsWith("https://ssl.jobcan.jp/login/")) {
        const waitForSPLogin = setInterval(() => {
            const clientInput = document.getElementById("client_id");
            const emailInput = document.getElementById("email");
            const passwordInput = document.getElementById("password");
            const loginButtons = document.getElementsByClassName("btn btn-info btn-block");
            if (clientInput && emailInput && passwordInput && loginButtons.length > 0) {
                clearInterval(waitForSPLogin);
                clientInput.value = clientId;
                emailInput.value = email;
                passwordInput.value = password;
                loginButtons[0].click();
            }
        }, 100);
    }
    // ② スマートフォン: ログイン後 → 打刻ページへ遷移
    else if (url === "https://ssl.jobcan.jp/m/index/index") {
        window.location.href = "https://ssl.jobcan.jp/m/work/accessrecord?_m=adit";
    }
    // ③ スマートフォン: 打刻ページで勤務状態に応じて自動打刻
    else if (url === "https://ssl.jobcan.jp/m/work/accessrecord?_m=adit") {
        const waitForStampPage = setInterval(() => {
            const button = document.getElementById("adit_item_1");
            const bodyText = document.body.innerText;
            if (button && bodyText) {
                clearInterval(waitForStampPage);
                const now = new Date();
                const hours = now.getHours();
                const minutes = now.getMinutes();
                if (bodyText.includes("未出勤") && hours >= 6 && hours < 10) {
                    button.click(); // 出勤
                } else if (bodyText.includes("勤務中") && (hours > 17 || (hours === 17 && minutes >= 30))) {
                    button.click(); // 退勤
                }
            }
        }, 200);
    }
    // ④ スマートフォン: 打刻完了後 → OmniFocus & Yahoo
    else if (url.startsWith("https://ssl.jobcan.jp/m/work/stampcomplete/")) {
        launchOmniFocusAndRedirect();
    }
    // ⑤ PC: ログインページで自動入力・ログイン → 社員ページへ遷移
    else if (url.startsWith("https://id.jobcan.jp/users/")) {
        const waitForPCLogin = setInterval(() => {
            const emailInput = document.getElementById("user_email");
            const passwordInput = document.getElementById("user_password");
            const loginButton = document.getElementById("login_button");
            if (emailInput && passwordInput && loginButton) {
                clearInterval(waitForPCLogin);
                emailInput.value = email;
                passwordInput.value = password;
                loginButton.click();
                setTimeout(() => {
                    window.location.href = 'https://ssl.jobcan.jp/employee';
                }, 2000);
            }
        }, 100);
    }
    // ⑥ PC: 社員ページで状態確認 → OmniFocus & Yahoo
    else if (url.startsWith("https://ssl.jobcan.jp/employee")) {
        function isInTimeRange(startHour, startMinute, endHour, endMinute) {
            const now = new Date();
            const start = new Date();
            start.setHours(startHour, startMinute, 0);
            const end = new Date();
            end.setHours(endHour, endMinute, 59);
            return now >= start && now <= end;
        }
        function checkForWorkingStatus() {
            const text = document.body.innerText;
            if (text.includes("勤務中")) {
                launchOmniFocusAndRedirect();
            }
        }
        function checkForExitStatus() {
            const text = document.body.innerText;
            if (text.includes("退室中")) {
                launchOmniFocusAndRedirect();
            }
        }
        if (isInTimeRange(6, 0, 17, 30)) {
            setInterval(checkForWorkingStatus, 1000); // 出勤チェック
        } else if (isInTimeRange(17, 31, 23, 59)) {
            setInterval(checkForExitStatus, 1000); // 退勤チェック
        }
    }
})();

使い方

const email = "メールアドレスまたはスタッフコード";
const password = "パスワード";
const clientId = "勤怠会社ID";

この部分へそれぞれ勤務先に応じた情報を入力します。
自動ログインの為にパスワードを入力する必要がありますが、勤怠管理専用のパスワードなので問題無いと私は思っています。
あとは、所属会社から付与されたジョブカン用のページへアクセスするだけで、自動化が完了します。

まとめ

TampermonkeyがiOSのSafariで正式対応したことで、日常のルーチン作業の半自動化が一気に現実的になりました。
特に私のように、「出退勤を忘れず、手間も減らしたい」というニーズがある人にとっては、Safari + Tampermonkey + iOSショートカット + OmniFocusの連携は非常に強力な組み合わせになるはずです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です