Skip to content

Instantly share code, notes, and snippets.

@upinetree
Last active June 28, 2019 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save upinetree/ce4c785b88e92cc96eba4384d366681e to your computer and use it in GitHub Desktop.
Save upinetree/ce4c785b88e92cc96eba4384d366681e to your computer and use it in GitHub Desktop.
Electron Fiddle Gist

使い方

Electron Fiddle で読み込んでビルド。

打刻しないモックを使うコードになっているので、使うときは renderer.js の以下を変更してください。

- // const touchProcess = touchStrategy;
- const touchProcess = touchStrategyMock;
+ const touchProcess = touchStrategy;
+ // const touchProcess = touchStrategyMock;

設定

~/jobcan/config.yml に以下を記述。

token: レガシートークン
channel: チャンネルid (チャンネル名だと見つからないことがあった(謎))
  • レガシートークンはこちらから
  • チャンネルIDはSlackのサイドバーから該当チャンネルを右クリックでリンクコピーして取得

出退勤画像

  • ~/jobcan/images/start/ 内に画像を入れると、出勤時にランダムで表示
  • ~/jobcan/images/finish/ 内に画像を入れると、退勤時にランダムで表示
  • /.+\.(png|jpg|jpeg|gif)/ に一致するファイルのみ
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
overflow: hidden;
}
.center {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 500px;
}
.result-image {
display: block;
width: 500px;
}
</style>
</head>
<body>
<div id='root' class='center'></div>
<script>
require('./renderer.js')
</script>
</body>
</html>
const {app, BrowserWindow} = require('electron')
let mainWindow
function createWindow () {
mainWindow = new BrowserWindow({
width: 500,
height: 500,
transparent: true,
frame: false,
alwaysOnTop: true,
// workaround for Mojave dark mode
// refs. https://github.com/electron/electron/issues/13164
titleBarStyle: 'customButtonsOnHover',
webPreferences: {
nodeIntegration: true,
}
})
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
app.on('ready', createWindow)
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
const fs = require('fs');
const sample = require('lodash.sample');
const axios = require('axios');
const qs = require('querystring');
const yaml = require('js-yaml');
function homePath(relativePath) {
const key = (process.platform == 'win32') ? 'USERPROFILE' : 'HOME';
return `${process.env[key]}/${relativePath}`;
}
function imagePath(relativePath) {
return homePath(`jobcan/images/${relativePath}`)
}
async function getLastMessage(channel, token) {
const endpoint = "https://slack.com/api/conversations.history"
const query = {
token: token,
channel: channel,
limit: 1
};
return await axios.get(endpoint, { params: query }).then((res) => {
console.log(res);
return res.data.messages[0].text;
})
.catch((err) => {
alert(`Slack request error: ${err}`);
});
}
async function jobcanCommand(command, channel, token) {
const endpoint = "https://slack.com/api/chat.command";
const query = qs.stringify({
token: token,
channel: channel,
command: `/${command}`,
as_user: 'true'
});
return await axios.post(endpoint, query).then((res) => {
console.log(res);
if (res.data.error) { alert(`Slack request error: ${res.data.error}`) }
})
.catch((err) => {
alert(`Slack request error: ${err}`);
});
}
function jobcanTouch(channel, token) {
return jobcanCommand('jobcan_touch', channel, token);
}
function jobcanWorktime(channel, token) {
return jobcanCommand('jobcan_worktime', channel, token);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function loadConfig() {
try {
return yaml.safeLoad(fs.readFileSync(homePath('jobcan/config.yml'), 'utf8'));
} catch(e) {
alert('Failed to laod config.yml');
}
}
const allowedExtensions = /.+\.(png|jpg|jpeg|gif)/
const touchStrategy = async ({channel, token}) => {
await jobcanTouch(channel, token);
await jobcanWorktime(channel, token);
await sleep(3000);
const state = await getLastMessage(channel, token).then(text => (
text.match(/勤務中/) ? 'start' : 'finish'
));
return state;
}
const touchStrategyMock = (_config) => {
const state = localStorage.getItem('jobcanState') || 'start';
localStorage.setItem('jobcanState', state === 'start' ? 'finish' : 'start');
return state;
}
// const touchProcess = touchStrategy;
const touchProcess = touchStrategyMock;
window.addEventListener('load', async () => {
const config = loadConfig();
const root = document.querySelector("#root");
const img = document.createElement('img');
img.classList.add('result-image');
const state = await touchProcess(config);
const imageNames = fs.readdirSync(imagePath(state)).filter(name => name.match(allowedExtensions));
img.setAttribute('src', imagePath(`${state}/${sample(imageNames)}`));
root.appendChild(img);
await sleep(3000);
close();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment