OSDN Git Service

Commit master
authorkokarare1212 <kokarare1212@gmail.com>
Sun, 17 May 2020 00:16:53 +0000 (09:16 +0900)
committerkokarare1212 <kokarare1212@gmail.com>
Sun, 17 May 2020 00:16:53 +0000 (09:16 +0900)
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
classi.pyw [new file with mode: 0644]
image/group2.png [new file with mode: 0644]
image/home.png [new file with mode: 0644]
image/like.png [new file with mode: 0644]
image/login.png [new file with mode: 0644]
requirements.txt [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..9638ed5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,161 @@
+![](https://img.shields.io/badge/Python-3.x.x-brightgreen?longCache=true)![](https://img.shields.io/badge/%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3-1.1.2.0-blue?longCache=true)
+# Classi-Student-Python
+Python製のClassi(クラッシー)の非公式クライアント
+## インストール方法
+### Windows
+単体で動かすことができます  
+またインストーラーもございます  
+バイナリ単体は `Classi.Windows.Binary.<Version>.zip` を  
+インストラーは `Classi.Windows.Installer.<Version>.exe`を  
+ご利用ください  
+[こちら](https://github.com/kokarare1212/Classi-Student-Python/releases/latest)からダウンロードできます
+### Mac
+単体で動かすことができます  
+`Classi.Mac.<Version>.zip` をご利用ください  
+[こちら](https://github.com/kokarare1212/Classi-Student-Python/releases/latest)からダウンロードできます
+### Linux
+単体で動かすことができます  
+`Classi.Linux.<Version>.zip` をご利用ください  
+[こちら](https://github.com/kokarare1212/Classi-Student-Python/releases/latest)からダウンロードできます
+### その他のOS
+Python3をインストールしていない人は[公式サイト](https://www.python.org/downloads/)からダウンロードしインストールするか  
+各パッケージマネージャーを使用してインストールしてください  
+また、Python3のライブラリ管理の「pip」も必要になります
+
+上の「Clone or Download」の「Download ZIP」からダウンロードするか、
+```CMD
+git clone https://github.com/kokarare1212/Classi-Student-Python.git
+```
+でダウンロードし解凍したディレクトリで
+```CMD
+python3 -m pip install -r requirements.txt
+```
+または
+```CMD
+python -m pip install -r requirements.txt
+```
+を実行し必要なモジュールをインストールしてください
+## 起動方法
+### Windows
+#### インストーラーの場合
+* インストーラーをダウンロードする
+* インストーラーを実行する
+* インストールした場所から `classi.exe` を実行するかスタートメニューから `Classi` を実行する
+#### バイナリの場合
+* ダウンロードしたファイルを任意の場所に解凍する
+圧縮ファイル内は以下のようになっています
+```TREE
+Classi.Windows.Binary.<Version>.zip
+└classi.exe
+```
+* `classi.exe` を実行する
+### Mac
+* ダウンロードしたファイルを任意の場所に解凍する  
+圧縮ファイル内は以下のようになっています
+```TREE
+Classi.Mac.<Version>.zip
+└┌classi
+ └classi.app
+```
+※二つのファイルは同じディレクトリに入れてください  
+* `classi` を実行する
+### Linux
+* ダウンロードしたファイルを任意の場所に解凍する
+圧縮ファイル内は以下のようになっています
+```TREE
+Classi.Linux.Binary.<Version>.zip
+└classi
+```
+* `classi.exe` を実行する
+### その他のOS
+* `classi.pyw` を実行する
+## 使い方
+### ログイン
+![](./image/login.png)
+* Classiの生徒アカウントでログインします  
+#### メニュー
+##### ファイル(F)  
+* 閉じる(X)  
+現在のウィンドウを閉じます
+##### ヘルプ(H)
+* このアプリについて(A)  
+アプリのクレジットを表示します
+#### ボタン
+* ログイン  
+ログインします  
+ログインに失敗した場合はダイアログが表示されます
+* 閉じる  
+現在のウィンドウを閉じます
+### ホーム
+![](./image/home.png)
+* アカウントの詳細情報が表示されます
+#### メニュー
+##### ファイル(F)  
+* 閉じる(X)
+現在のウィンドウを閉じます
+##### ヘルプ(H)
+* このアプリについて(A)
+アプリのクレジットを表示します
+#### ボタン
+* 校内グループ  
+ウィンドウ `校内グループ` を表示します
+* ログアウト
+現在のユーザーをログアウトします
+* 閉じる  
+現在のウィンドウを閉じます
+### 校内グループ
+![](./image/group2.png)
+#### メニュー
+##### ファイル(F)  
+* 開く(O)  
+画面右下のリストの選択されたURLをブラウザで開きます
+* 上書き保存(S)  
+一度保存されていた場合上書き保存されます  
+されていない場合は `名前をつけて保存(A)` と同機能
+* 名前をつけて保存(A)  
+画面右上に表示されているテキストを保存します
+* 閉じる(X)  
+現在のウィンドウを閉じます
+##### 編集(E)
+* コピー(C)  
+画面右上に表示されているテキストの選択部分をクリップボードにコピーします
+##### ヘルプ(H)
+* このアプリについて(A)  
+アプリのクレジットを表示します
+#### ボタン
+* 表示  
+画面左の日付の選択されているリストの詳細を画面右上に表示します
+* 再読み込み  
+サーバーから校内グループの情報を再読み込みします
+* 開く  
+画面右下のリストの選択されたURLをブラウザで開きます
+* 見ました  
+画面左の日付の選択されているリストのウィンドウ `見ました` を表示します
+* 閉じる  
+現在のウィンドウを閉じます
+### 見ました
+![](./image/like.png)
+#### メニュー
+##### ファイル(F)  
+* 上書き保存(S)  
+一度保存されていた場合上書き保存されます  
+されていない場合は `名前をつけて保存(A)` と同機能
+* 名前をつけて保存(A)  
+画面下に表示されているテキストを保存します
+* 閉じる(X)  
+現在のウィンドウを閉じます
+##### 編集(E)
+* コピー(C)  
+画面下に表示されているテキストの選択部分をクリップボードにコピーします
+##### ヘルプ(H)
+* このアプリについて(A)  
+アプリのクレジットを表示します
+#### ボタン
+* 詳細  
+画面上の名前の選択されているリストの詳細を画面下に表示します
+* 見ました  
+画面左の日付の選択されているリストのウィンドウ `見ました` を表示します
+* 再読み込み  
+サーバーから `見ました` の情報を再読み込みします
+* 閉じる  
+現在のウィンドウを閉じます
\ No newline at end of file
diff --git a/classi.pyw b/classi.pyw
new file mode 100644 (file)
index 0000000..9f1158a
--- /dev/null
@@ -0,0 +1,266 @@
+# -*- coding: utf-8 -*-
+import PySimpleGUI as sg
+import tkinter as tk
+import requests, re, os, pyperclip, sys, webbrowser, json, glob
+token = ""
+flag = True
+def login():
+   global token
+   flag = True
+
+   sg.theme('Dark Blue 3')
+
+   menu = [
+      ["ファイル(F)", ["閉じる(X)"]],
+      ["ヘルプ(H)", ["このアプリについて(A)"]]
+   ]
+
+   layout = [
+      [sg.Menu(menu, tearoff=False, pad=(200, 1))],
+      [sg.Text('ログイン | Classi')],
+      [sg.Text('ID', size=(15, 1)), sg.InputText("", key="id")],
+      [sg.Text('パスワード', size=(15, 1)), sg.InputText("", password_char="*", key="pass")],
+      [sg.Submit(button_text='ログイン'), sg.Submit(button_text='閉じる')]
+   ]
+
+   window = sg.Window('ログイン | Classi', layout)
+
+   while True:
+      event, values = window.read()
+
+      if event is None or event == "閉じる(X)" or event == "閉じる":
+        break
+
+      if event == "ログイン":
+         s = requests.Session()
+         r = s.get("https://auth.classi.jp/students")
+         authToken = re.search(r"name=\"authenticity_token\"\svalue=\"(.+)\"", r.text).group(1)
+         r = s.post("https://auth.classi.jp/login/validate", data={"utf8": "✓", "authenticity_token": authToken, "classi_id": values["id"], "password": values["pass"], "remember_me": "on", "button": "", "login_form": "student"}, allow_redirects=False)
+         cookies = r.headers["Set-Cookie"]
+         tokenre = re.search(r"classi_account.(.+)\;.domain", cookies)
+         if tokenre is None:
+            sg.popup("ID又はパスワードが違います", title="ログイン | Classi")
+            continue
+         token = tokenre.group(1)
+         with open(os.path.dirname(os.path.abspath(__file__))+"/token.classi", "w") as f:
+            f.write(token)
+            flag = False
+         break
+      if event == "このアプリについて(A)":
+         sg.popup("Classi\n©2020 kokarare1212 All rights reserved.", title="このアプリについて | Classi")
+   window.close()
+   if flag:
+      sys.exit()
+   homemenu()
+
+def likes(talk):
+   global token
+   if talk is None or talk == "":
+      return
+   m = requests.get("https://platform.classi.jp/api/v2/groups/1001309/likes?message_id="+str(talk["message"]["id"])+"&type=1", headers={"Cookie": "classi_account="+token}).text
+   r = json.loads(m)
+   likeuserlist = r["like_users"]
+   likeuser = []
+   for l in likeuserlist:
+      likeuser.append(l["name"])
+   menu = [
+      ["ファイル(F)", ["上書き保存(S)", "名前を付けて保存(A)", "閉じる(X)"]],
+      ["編集(E)", ["コピー(C)"]],
+      ["ヘルプ(H)", ["このアプリについて(A)"]]
+   ]
+   layout = [
+      [sg.Menu(menu, tearoff=False, pad=(200, 1))],
+      [sg.Text('見ました | Classi')],
+      [sg.Text("済:"+str(len(likeuser))+"人", key="total")],
+      [sg.Listbox(likeuser, size=(40,10), enable_events=True, key='_USER_')],
+      [sg.MLine(size=(40,3), key='_DISC_', disabled=True)],
+      [sg.Submit(button_text="詳細"), sg.Submit(button_text="見ました"), sg.Submit(button_text="再読み込み"), sg.Submit(button_text="閉じる")]
+   ]
+   filePath = ""
+   window = sg.Window('見ました | Classi', layout, right_click_menu=["メニュー", "コピー(C)"])
+   while True:
+      event, values = window.Read()
+      if event is None or event == "閉じる(X)" or event == "閉じる":
+         break
+      if event == "詳細":
+         if values["_USER_"] == []:
+            return
+         window.Element("_DISC_").update(likeuserlist[likeuser.index(values["_USER_"][0])]["name"]+"\n"+likeuserlist[likeuser.index(values["_USER_"][0])]["belonging_name"]+"\n"+likeuserlist[likeuser.index(values["_USER_"][0])]["like_date"])
+      if event == "見ました":
+         r = requests.post("https://platform.classi.jp/api/v2/groups/"+str(talk["group"]["id"])+"/likes", headers={"Content-Type": "application/x-www-form-urlencoded", "Cookie": "classi_account="+token}, data={"id": talk["message"]["id"], "type": "1"})
+         if r.text == "{\"message\":\"すでに「見ました」と言っています。\"}":
+            sg.popup("すでに「見ました」と言っています。", title="見ました | Classi")
+         r = requests.get("https://platform.classi.jp/api/v2/groups/1001309/likes?message_id="+str(talk["message"]["id"])+"&type=1", headers={"Cookie": "classi_account="+token}).json()
+         likeuserlist = r["like_users"]
+         likeuser = []
+         for l in likeuserlist:
+            likeuser.append(l["name"])
+         window.Element("_USER_").update(likeuser)
+         window.Element("total").update("済:"+str(len(likeuser))+"人")
+      if event == "再読み込み":
+         r = requests.get("https://platform.classi.jp/api/v2/groups/1001309/likes?message_id="+str(talk["message"]["id"])+"&type=1", headers={"Cookie": "classi_account="+token}).json()
+         likeuserlist = r["like_users"]
+         likeuser = []
+         for l in likeuserlist:
+            likeuser.append(l["name"])
+         window.Element("_USER_").update(likeuser)
+         window.Element("total").update("済:"+str(len(likeuser))+"人")
+      if event == "コピー(C)":
+         try:
+            selected = window["_DISC_"].TKText.selection_get()
+         except tk._tkinter.TclError:
+            pass
+         else:
+            pyperclip.copy(selected)
+      if event == "上書き保存(S)":
+         if filePath == "":
+            m = tk.filedialog.asksaveasfile(defaultextension='txt' , filetypes=[('テキスト', '*.txt'), ('すべてのファイル', '')] , title='保存')
+         if m is None:
+            continue
+         filePath = m.name
+         with open(filePath, "w") as f:
+            f.write(values["_DISC_"])
+      if event == "名前を付けて保存(A)":
+         m = tk.filedialog.asksaveasfile(defaultextension='txt' , filetypes=[('テキスト', '*.txt'), ('すべてのファイル', '')] , title='保存')
+         if m is None:
+            continue
+         filePath = m.name
+         with open(filePath, "w") as f:
+            f.write(values["_DISC_"])
+      if event == "このアプリについて(A)":
+         sg.popup("Classi\n©2020 kokarare1212 All rights reserved.", title="このアプリについて | Classi")
+   window.close()
+
+def group2():
+   global token
+   if os.path.isfile(os.path.dirname(os.path.abspath(__file__))+"/group2.classi"):
+      with open(os.path.dirname(os.path.abspath(__file__))+"/group2.classi", "r") as f:
+         r = f.read()
+   else:
+      r = requests.get("https://platform.classi.jp/api/v2/groups/newmessages", headers={"Cookie": "classi_account="+token}).text
+      with open(os.path.dirname(os.path.abspath(__file__))+"/group2.classi", "w") as f:
+         f.write(r)
+   groupList = json.loads(r)
+   dateList = []
+   for group in groupList:
+      dateList.append(group["message"]["created_at"])
+   menu = [
+      ["ファイル(F)", ["開く(O)", "上書き保存(S)", "名前を付けて保存(A)", "閉じる(X)"]],
+      ["編集(E)", ["コピー(C)"]],
+      ["ヘルプ(H)", ["このアプリについて(A)"]]
+   ]
+   col = [
+      [sg.MLine(size=(100,25), key='_TALK_', disabled=True)],
+      [sg.Listbox([], size=(100,3), enable_events=True, key='_URL_LIST_')]
+   ]
+   layout = [
+      [sg.Menu(menu, tearoff=False, pad=(200, 1))],
+      [sg.Text('校内グループ | Classi')],
+      [sg.Listbox(dateList, size=(20,28), enable_events=True, key='_MESSAGE_LIST_'), sg.Column(col)],
+      [sg.Submit(button_text='表示'), sg.Submit(button_text="再読み込み"), sg.Submit(button_text="開く"), sg.Submit(button_text="見ました"), sg.Submit(button_text="閉じる")],
+   ]
+   window = sg.Window('校内グループ | Classi', layout, right_click_menu=["メニュー", "コピー(C)"])
+   filePath = ""
+   while True:
+      event, values = window.Read()
+      if event is None or event == "閉じる(X)" or event == "閉じる":
+         break
+      if event == "表示":
+         if values["_MESSAGE_LIST_"] != []:
+            window.Element('_TALK_').Update(groupList[dateList.index(values["_MESSAGE_LIST_"][0])]["message"]["body"]["text"])
+            urls = re.findall(r"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", groupList[dateList.index(values["_MESSAGE_LIST_"][0])]["message"]["body"]["text"])
+            window.Element("_URL_LIST_").update(urls)
+      if event == "再読み込み":
+         r = requests.get("https://platform.classi.jp/api/v2/groups/newmessages", headers={"Cookie": "classi_account="+token}).text
+         with open(os.path.dirname(os.path.abspath(__file__))+"/group2.classi", "w") as f:
+            f.write(r)
+         talkList = json.loads(r)
+         dateList = []
+         for talk in talkList:
+            dateList.append(talk["message"]["created_at"])
+         window.Element('_MESSAGE_LIST_').Update(dateList)
+      if event == "コピー(C)":
+         try:
+            selected = window["_TALK_"].TKText.selection_get()
+         except tk._tkinter.TclError:
+            pass
+         else:
+            pyperclip.copy(selected)
+      if event == "上書き保存(S)":
+         if filePath == "":
+            m = tk.filedialog.asksaveasfile(defaultextension='txt' , filetypes=[('テキスト', '*.txt'), ('すべてのファイル', '')] , title='保存')
+         if m is None:
+            continue
+         filePath = m.name
+         with open(filePath, "w") as f:
+            f.write(values["_TALK_"])
+      if event == "名前を付けて保存(A)":
+         m = tk.filedialog.asksaveasfile(defaultextension='txt' , filetypes=[('テキスト', '*.txt'), ('すべてのファイル', '')] , title='保存')
+         if m is None:
+            continue
+         filePath = m.name
+         with open(filePath, "w") as f:
+            f.write(values["_TALK_"])
+      if event == "開く" or event == "開く(O)":
+         if values["_URL_LIST_"] == []:
+            continue
+         webbrowser.open(values["_URL_LIST_"][0])
+      if event == "見ました":
+         if values['_MESSAGE_LIST_'] == []:
+            continue
+         likes(groupList[dateList.index(values["_MESSAGE_LIST_"][0])])
+      if event == "このアプリについて(A)":
+         sg.popup("Classi\n©2020 kokarare1212 All rights reserved.", title="このアプリについて | Classi")
+   window.Close()
+
+def homemenu():
+   global token
+   if os.path.isfile(os.path.dirname(os.path.abspath(__file__))+"/profile.classi"):
+      with open(os.path.dirname(os.path.abspath(__file__))+"/profile.classi", "r") as f:
+         me = json.loads(f.read())
+   else:
+      r = requests.get("https://partner.classi.jp/classi/api/me", headers={"Cookie": "classi_account="+token}) 
+      me = r.json()
+      with open(os.path.dirname(os.path.abspath(__file__))+"/profile.classi", "w") as f:
+         f.write(r.text)
+   menu = [
+      ["ファイル(F)", ["閉じる(X)"]],
+      ["ヘルプ(H)", ["このアプリについて(A)"]]
+   ]
+   layout = [
+      [sg.Menu(menu)],
+      [sg.Text("ホーム | Classi")],
+      [sg.Text(me["dimensions"]["dimension3"]+"\n"+me["dimensions"]["dimension10"]+" "+me["dimensions"]["dimension11"]+"\n"+me["name"])],
+      [sg.Submit("校内グループ")],
+      [sg.Submit("ログアウト")],
+      [sg.Submit("閉じる")]
+   ]
+   window = sg.Window("ホーム | Classi", layout, size=(200,200))
+   flag = False
+   while True:
+      event, values = window.read()
+      if event is None or event == "閉じる(X)" or event == "閉じる":
+         break
+      if event == "校内グループ":
+         group2()
+      if event == "このアプリについて(A)":
+         sg.popup("Classi\n©2020 kokarare1212 All rights reserved.", title="このアプリについて | Classi")
+      if event == "ログアウト":
+         remove_glob(os.path.dirname(os.path.abspath(__file__))+"/*.classi")
+         flag = True
+         break
+   window.close()
+   if flag:
+      token = ""
+      login()
+def remove_glob(pathname, recursive=True):
+    for p in glob.glob(pathname, recursive=recursive):
+        if os.path.isfile(p):
+            os.remove(p)
+if os.path.isfile(os.path.dirname(os.path.abspath(__file__))+"/token.classi"):
+   with open(os.path.dirname(os.path.abspath(__file__))+"/token.classi", "r") as f:
+      token = f.read()
+if token == "":
+   login()
+else:
+   homemenu()
\ No newline at end of file
diff --git a/image/group2.png b/image/group2.png
new file mode 100644 (file)
index 0000000..52298d6
Binary files /dev/null and b/image/group2.png differ
diff --git a/image/home.png b/image/home.png
new file mode 100644 (file)
index 0000000..0a940b3
Binary files /dev/null and b/image/home.png differ
diff --git a/image/like.png b/image/like.png
new file mode 100644 (file)
index 0000000..26e99f5
Binary files /dev/null and b/image/like.png differ
diff --git a/image/login.png b/image/login.png
new file mode 100644 (file)
index 0000000..e3b969c
Binary files /dev/null and b/image/login.png differ
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..1cbb83b
--- /dev/null
@@ -0,0 +1,9 @@
+##########################
+#Classi Requirements File#
+#                        #
+#©2020 kokarare1212      #
+#    All rights reserved.#
+##########################
+PySimpleGUI
+requests
+pyperclip
\ No newline at end of file