Code

デスクトップが散らかってると怒られる「おかんアプリ」を作ってみた。

油断するとデスクトップがアイコンだらけになってしまう私、、、
学生のころなら、机の上が散らかっていたらお母さんに「片づけなさい!!」って怒られたものです。
あんな感じで、デスクトップが散らかっていたら怒るアプリが作れないかと考えてみました。


プログラム概要

主な使用ライブラリ:pysimpleGUI,pyinstaller他
やりたかったこと:デスクトップに表示しているアイコンで一定期間更新されていないものがあればアラートを表示するデスクトップアプリ。

要件定義

  • 毎朝デスクトップディレクトリを確認
  • 一定期間更新されていないファイルの一覧を取得
  • もし該当ファイルがあればアラートを出す
  • こんなアプリがPythonで作れないか?  

    毎朝デスクトップディレクトリを確認

    標準モジュールのglobモジュールで、デスクトップディレクトリ内の全ファイル名を取得。

        import glob
        desktop_path = "C:\Users\user\Desktop" #デスクトップディレクトリのパス
        files = glob.glob(f"{desktop_path}/*")

    これで、filesという変数にデスクトップにあるすべてのファイルがLISTとして格納される。


    一定期間更新されていないファイルの一覧を取得

    osモジュールのos.path.getmtimeでファイルの更新日時を取得。

        import os
        last_updated = os.path.getmtime(file) #最終更新日のデータを取得。
        last_updated_day = datetime.datetime.fromtimestamp(last_updated) #datetime型に変換。

    今日の日付と比較して何日前かを取得する。

    #整理されてないリストの作成
        import glob
        import os
        import datetime
        now = datetime.datetime.now()
        files = glob.glob(f"{desktop_path}/*")
        trash_list =[]
        for file in files:
            last_updated = os.path.getmtime(file)
            last_updated_day = datetime.datetime.fromtimestamp(last_updated)
            duration = (now - last_updated_day).days #最終更新からの経過日数
            filename = os.path.split(file)[-1] #ファイル名と拡張子のみ取得
            if duration >= 7: #今回は7日以上更新されていないものをリストへ追加。
                trash_list.append([filename,duration])
        trash_list = sorted(trash_list, reverse=True, key=lambda x: x[1])#古い順にソート

    これでリストは作成出来る。後はGUI表示。


    もし該当ファイルがあればアラートを出す

    せっかくなら怒っているおかんのイラストを入れたい。pysympleGUIで画像を入れたGUI画面の作成。

    今回の目玉。すっごい簡単なコードでGUI画面をサクッと作成出来る。

        import PySimpleGUI as sg
        #GUI画面の構成はリストのリストで作成。
        layout = [[sg.Text("日以上変更ないファイルよ!片付けなさい!!!",font=50)],
                  [sg.Image('./okan_mini.png'),sg.Text("hoge")],
                  [sg.Button('は~い', key="fin")]]
    
        window = sg.Window("片づけなさい", layout=layout)
        #画面表示はwhileループで。中止するまで表示し続ける、というイメージ。
        while True:
            event, value = window.read()

    これで最低限の画面構成は完成。あと変数部分を足してやる。

    arart

    他に追加機能として、2つCSVファイルを用意。

    名前を書いたファイルはおいていても文句を言われない、exception.csv

    exception.csv
    name
    desktop.ini

    desktop.iniは必ずあるファイルなので書いておく。あとゴミ箱とかも。

    あと一つ、config.csvで、何日放置で怒るか。ウインドウタイトル。デスクトップパス。を設定可能に。

    config.csv
    key value
    grace_period(days) 7
    message 片付けなさいよ
    desktop_pass C:/Users/user/Desktop
        #okan_app.py全文
        import glob
        import os
        import datetime
        import pandas as pd
        import PySimpleGUI as sg
        now = datetime.datetime.now()
        #config読み込み
        data = pd.read_csv("config.csv")
        arg_df = data[["key", "value"]].values
        grace_period, message ,desktop_path = [int(arg_df[0][1]),arg_df[1][1],arg_df[2][1]]
    
        #例外ファイル読み込み
        exception_data = pd.read_csv("exception.csv")
        exception_list = exception_data["name"].values.tolist()
    
        files = glob.glob(f"{desktop_path}/*")
        def checker():
            #整理されてないリストの作成
            trash_list =[]
            trashes = ""
            for file in files:
                last_updated = os.path.getmtime(file)
                last_updated_day = datetime.datetime.fromtimestamp(last_updated)
                duration = (now - last_updated_day).days
                filename = os.path.split(file)[-1]
                if filename in exception_list:
                    pass
                else:
                    if duration >= grace_period:
                        trash_list.append([filename,duration])
            trash_list = sorted(trash_list, reverse=True, key=lambda x: x[1])#古い順にソート
            if len(trash_list) == 0:
                pass
            else:
                #GUI表示
                for trash in trash_list:
                    trashes = trashes + f"{trash[0]} 最終更新日より{trash[1]}日\n"
    
                layout = [[sg.Text(f"{grace_period}日以上変更ないファイルよ!片付けなさい!!!",font=50)],[sg.Image('./okan_mini.png'),sg.Text(trashes)],
                          [sg.Button('は~い', key="fin")]]
    
                window = sg.Window(message, layout=layout)
    
                while True:
                    event, value = window.read()  # ここで入力待ち状態になる
                    # ボタンのクリック等のイベントを(key, value)で受け取る
    
                    if event == sg.WIN_CLOSED or "fin":
                        break
    
                    window.close()
    
        if __name__ == '__main__':
            checker()

    これで完成。なかなかいい感じ

    result

    いらすとやさん、ありがとうございます。



    パッケージ化してタスクスケジューラで自動起動

    pyinstallerというライブラリを利用することで、exe化してpythonの入っていない端末でも利用が可能。

    いい出来なので人にも使わせたいと思いパッケージ化。

     $ pyinstaller ○○.py --onefile

    これだけでexeファイルを作成してくれる。(多少重たいのが難点だが。)

    pythonRPAでも紹介したが、タスクスケジューラに指定するとき注意。

    タスクスケジューラに直接exeファイルを指定してやると関連ファイル(config.csv等)を読み込んでもらえなくてエラーとなる。

    タスクスケジューラでのプログラム起動では相対パス指定を受け付けてもらえないようで、、

     @echo off
     okan_app.exe

    同一ディレクトリにこんな感じのbatファイルを作成してこちらを起動してやるとちゃんと直下のファイルを読み込んでもらえる。

    タスクスケジューラへの登録はこんな感じ。

    tasks

    開始オプションにディレクトリ名を指定してやらないと動かなかった。(環境による模様)


    まとめ

    GUIがめっちゃ簡単に作れるpysimpleGUI楽しい!!!
    本当に最低限の機能しか使ってないので、もっといろいろやってみよう。
    pandasを使う必要性はほぼ皆無ですね。これを省けばもっと軽いアプリになるはず(汗)
    ネタ的に作ってみましたが、結構便利。毎朝口うるさくアラートを出してくれるため、デスクトップ綺麗に保ててます。