LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

有能執事くん_アプリ版

Last updated at Posted at 2022-06-11

執事くん

こちらのバッチ版を、デスクトップアプリ版にしたもの。
Windows用です。
Electronにて実装しました。頒布はここクリックでDL
zip展開後にREADME.mdがあるので、したがってインストールバッチを実行してください。
起動すると、ランダムなローディングアニメーションが流れたのち、以下のホーム画面が表示されます。
image.png

バッチ版との差異

バッチ版の弱点として、フォルダを自動で作成し、構成を縛る、というものがありました。
こちらのアプリでは設定機能にて、本アプリで使用するフォルダを指定することができます。
image.png

実装機能

・ファイル/リンク群を起動
・バックアップ
・バックアップ転送
・リンク群のフォルダをエクスプローラで開く
となります。ボタンホバーで説明文が表示されるのでチュートリアルは不要でしょう。

バッチ版と違い、追加バッチを呼び出す機能はありません。
そこまでこの機能が活躍することがないと判断し、今回のアプリでは淘汰されました。。。

また、バックアップ進捗バーや圧縮アニメなど、視覚的な機能の向上がメインとなっているうえ
大きなファイルを圧縮する際には、内臓した7zipを用いた圧縮を使用します。

ノンビルドでzipを配布しているのでソースは見放題です。ご自由にカスタムできます。
Electron以外の実装部分ソースの一部を以下で紹介したいと思います。

ソース

全量はこちら

バックアップ機能部分のソース.js
// ========================================
// BK機能用画面をロード
// ========================================
import Forge from '../../core/Forge.js'
import CMD from '../../core/CMD.js'
import Fsys from '../../core/Fsys.js'

// exeファイルのあるディレクトリを取得
const chdir = CMD.cmdSync('chdir').replace(/\r\n/g, '');

// config.json
const cfDict = JSON.parse(
  Fsys.read(`${chdir}\\src\\config.json`)
  .replace(/\r\n/g, ''));

// タイトルを設定
const setTitle = v => document.querySelector('#title').innerHTML = v;

// 進捗バー
let progress = document.querySelector('.progress-bar');

// 作業フォルダをハンドリング
function handl() {
  setTitle('ハンドリング開始');
  if (!Fsys.existance(cfDict['bkto'])
    || !Fsys.existance(cfDict['bkfrom'])) {
    Forge.load('contents', 'home', () => {
      document.querySelector('#console').innerHTML = 'BKフォルダが存在しません, 設定画面から設定してください。';
    });
    return false;
  }
  return true;
}

let bktoDirName = null;
let bkFileAllNo = null;

// 実行関数
function exeBk() {
  setTitle('処理開始');
  let now = new Date();
  let yyyy = now.getFullYear();
  let mm = now.getMonth() >= 9 ? now.getMonth() + 1 : `0${now.getMonth() + 1}`;
  let dd = now.getDate();
  // 新規ヘッダ or 今日と同日でない場合
  let dirname = `${cfDict['bkheader']}_${yyyy}_${mm}_${dd}_ver1`;
  let flist = Fsys.fList(cfDict['bkto']);
  let dirList = Fsys.dirList(cfDict['bkto']);
  if (flist || dirList) {
    // ファイル名も考慮
    // 同ヘッダファイルについて
    let sameHeadFile = flist
      ? flist.concat(dirList).filter(v => v)
        .filter(v => v.startsWith(cfDict['bkheader'])).sort()
      : dirList.concat(flist).filter(v => v)
        .filter(v => v.startsWith(cfDict['bkheader'])).sort();
    if (sameHeadFile.length != 0) {
      // 最新バージョンを取得
      let el = /(.+)_(.+)_(.+)_(.+)_ver(.+)/.exec(sameHeadFile.slice(-1)[0]);
      // 今日と同日なら, バージョンを+1
      if (el[2] == yyyy && el[3] == mm && el[4] == dd) {
        // ファイルの場合拡張子を削除
        let ver = el[5].split('.')[0];
        dirname = `${cfDict['bkheader']}_${yyyy}_${mm}_${dd}_ver${Number(ver) + 1}`;
      }
    }
  }
  setTitle('名前ok');
  bktoDirName = `${cfDict['bkto']}\\${dirname}`;
  new Promise(resolve => {
    // フォルダ作成
    setTitle('フォルダ作成を開始');
    let reMkdir = Fsys.mkdir(bktoDirName);
    setTitle('フォルダ作成完了' + reMkdir);
    resolve();
  })
  .then(() => {
    // 並列でコピー、進捗を監視して圧縮/転送
    setTitle('コピー開始');
    let resRobocp = Fsys.robocopy(cfDict['bkfrom'], bktoDirName);
    setTitle('robocopyコマンド 結果' + resRobocp);
    let asdasd = Fsys.count(cfDict['bkfrom']);
    setTitle('カウント 結果' + asdasd);
    calcProgress(Fsys.count(cfDict['bkfrom']));
  });
}

// 進捗監視, 圧縮, 転送
function calcProgress(bkAll) {
  if (!bkAll) {
    calcProgress(Fsys.count(cfDict['bkfrom']));
    return;
  }
  let transfared = 0;
  try {
    transfared = Number(Fsys.count(bktoDirName));
  } catch(e) {
    // 0件
  }
  setTitle(`コピー中(${transfared}/${bkAll})`);
  progress.style.width = `${Math.floor(transfared/bkAll*100)}%`;// 進捗バー更新
  if (transfared >= bkAll) {
    // コピー完了
    new Promise(resolve => {
      progress.style.width = `100%`;
      setTitle(`コピー完了`);
      setTimeout(() => resolve(), 300);
    })
    // 圧縮画面表示
    .then(() => new Promise(resolve => {
      setTitle('圧縮中...');
      document.querySelector('.progress-base').style.display = 'none';
      document.querySelector('.bg').classList.add('compress');
      setTimeout(() => resolve(), 2000);
    }))
    // 圧縮/コピーフォルダ削除
    .then(() => new Promise(resolve => {
      let resComp = Fsys.compress(bktoDirName);
      if (!resComp) {
        setTitle('圧縮失敗 7zipでリトライ');
        let resSeven = CMD.cmdSync(`${chdir}\\src\\lib\\7za.exe a ${bktoDirName}.zip ${bktoDirName}`);
        setTitle(resSeven);
      }
      let resDel = Fsys.delCmd(bktoDirName);
      if (!resDel) {
        setTitle('BK用にコピーしたファイルを削除できませんでした');
      }
      // いずれかに失敗した場合、ここで終了
      if (!resComp || !resDel) {
        return;
      }
      if (resComp && resDel) {
        setTitle('圧縮完了');
      }
      resolve();
    }))
    // 転送しない場合は終了
    .then(() => new Promise(resolve => {
      if (!Fsys.existance(cfDict['sendto'])) {
        setTimeout(() => {
          Forge.load('contents', 'home');
        }, 1000);
        return;
      }
      resolve();
    }))
    // 転送画面表示
    .then(() => new Promise(resolve => {
      setTitle('転送中...');
      document.querySelector('.bg').classList.remove('compress');
      document.querySelector('.bg').classList.add('transfar');
      setTimeout(() => resolve(), 1000);
    }))
    // 転送
    .then(() => new Promise(resolve => {
      Fsys.cpSync(`${bktoDirName}.zip`, cfDict['sendto']);
      setTitle('転送完了');
      setTimeout(() => {
        document.querySelector('.bg').classList.remove('transfar')
        Forge.load('contents', 'home');
        resolve();
      }, 1000);
    }));
    return;
  }
  // コピーが完了するまで再帰
  setTimeout(() => calcProgress(bkAll), 100);
}

// ハンドリングして実行
setTitle('処理を開始します');
if (handl()) {
  exeBk();
}

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up