From 12ee7eee2db2120e851093d9d8ab1a2b9f420af9 Mon Sep 17 00:00:00 2001 From: 24_OskinEA <24_OskinEA@iux.local> Date: Sun, 24 May 2026 13:51:49 +0300 Subject: [PATCH] Add alpha and beta versions --- alpha/gitea_simple_app/README.md | 31 ++ alpha/gitea_simple_app/README_START.md | 24 ++ .../__pycache__/api.cpython-312.pyc | Bin 0 -> 2553 bytes .../__pycache__/parser.cpython-312.pyc | Bin 0 -> 1148 bytes alpha/gitea_simple_app/api.py | 63 ++++ alpha/gitea_simple_app/build_windows_exe.bat | 6 + alpha/gitea_simple_app/main.py | 120 ++++++ alpha/gitea_simple_app/parser.py | 20 + alpha/gitea_simple_app/requirements.txt | 1 + alpha/gitea_simple_app/run_linux.sh | 3 + alpha/gitea_simple_app/run_windows.bat | 4 + beta1/gitea_analyzer_app/README.md | 46 +++ .../__pycache__/api.cpython-312.pyc | Bin 0 -> 3828 bytes .../__pycache__/parser.cpython-312.pyc | Bin 0 -> 1269 bytes .../__pycache__/storage.cpython-312.pyc | Bin 0 -> 3626 bytes beta1/gitea_analyzer_app/api.py | 81 ++++ beta1/gitea_analyzer_app/build_exe.bat | 11 + beta1/gitea_analyzer_app/main.py | 345 ++++++++++++++++++ beta1/gitea_analyzer_app/parser.py | 22 ++ beta1/gitea_analyzer_app/requirements.txt | 2 + beta1/gitea_analyzer_app/storage.py | 76 ++++ .../README.md | 38 ++ .../analyzer.py | 99 +++++ .../universal_git_analyzer_gui_final2/main.py | 244 +++++++++++++ .../requirements.txt | 1 + .../universal_git_analyzer_gui_final2/run.sh | 3 + .../storage.py | 65 ++++ 27 files changed, 1305 insertions(+) create mode 100644 alpha/gitea_simple_app/README.md create mode 100644 alpha/gitea_simple_app/README_START.md create mode 100644 alpha/gitea_simple_app/__pycache__/api.cpython-312.pyc create mode 100644 alpha/gitea_simple_app/__pycache__/parser.cpython-312.pyc create mode 100644 alpha/gitea_simple_app/api.py create mode 100644 alpha/gitea_simple_app/build_windows_exe.bat create mode 100644 alpha/gitea_simple_app/main.py create mode 100644 alpha/gitea_simple_app/parser.py create mode 100644 alpha/gitea_simple_app/requirements.txt create mode 100755 alpha/gitea_simple_app/run_linux.sh create mode 100644 alpha/gitea_simple_app/run_windows.bat create mode 100644 beta1/gitea_analyzer_app/README.md create mode 100644 beta1/gitea_analyzer_app/__pycache__/api.cpython-312.pyc create mode 100644 beta1/gitea_analyzer_app/__pycache__/parser.cpython-312.pyc create mode 100644 beta1/gitea_analyzer_app/__pycache__/storage.cpython-312.pyc create mode 100644 beta1/gitea_analyzer_app/api.py create mode 100644 beta1/gitea_analyzer_app/build_exe.bat create mode 100644 beta1/gitea_analyzer_app/main.py create mode 100644 beta1/gitea_analyzer_app/parser.py create mode 100644 beta1/gitea_analyzer_app/requirements.txt create mode 100644 beta1/gitea_analyzer_app/storage.py create mode 100644 beta2/universal_git_analyzer_gui_final2/README.md create mode 100644 beta2/universal_git_analyzer_gui_final2/analyzer.py create mode 100644 beta2/universal_git_analyzer_gui_final2/main.py create mode 100644 beta2/universal_git_analyzer_gui_final2/requirements.txt create mode 100755 beta2/universal_git_analyzer_gui_final2/run.sh create mode 100644 beta2/universal_git_analyzer_gui_final2/storage.py diff --git a/alpha/gitea_simple_app/README.md b/alpha/gitea_simple_app/README.md new file mode 100644 index 0000000..25b524e --- /dev/null +++ b/alpha/gitea_simple_app/README.md @@ -0,0 +1,31 @@ +# Gitea Repository Analyzer + +Программа для анализа репозиториев Gitea. + +## Возможности + +- получение информации о репозитории +- вывод автора +- вывод соавторов +- даты создания и изменения +- подсчёт строк Python-кода + +## Запуск + +```bash +pip install -r requirements.txt +python main.py + +--- + +# 🚀 Как загрузить на Gitea + +--- + +# 1. Создать репозиторий + +На Gitea: +- New Repository +- например: +```text +gitea-analyzer \ No newline at end of file diff --git a/alpha/gitea_simple_app/README_START.md b/alpha/gitea_simple_app/README_START.md new file mode 100644 index 0000000..f431128 --- /dev/null +++ b/alpha/gitea_simple_app/README_START.md @@ -0,0 +1,24 @@ +# Gitea Analyzer Simple + +Простая версия без логина и пароля. + +## Linux / Ubuntu + +```bash +sudo apt install python3-tk -y +pip3 install -r requirements.txt +python3 main.py +``` + +Или: + +```bash +./run_linux.sh +``` + +## Windows + +1. Установить Python. +2. Запустить `run_windows.bat`. + +Для сборки exe запустить `build_windows_exe.bat`. diff --git a/alpha/gitea_simple_app/__pycache__/api.cpython-312.pyc b/alpha/gitea_simple_app/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8c8b06eca79eebd736d3f161a167dca604cf8b8 GIT binary patch literal 2553 zcmc&#O-vhC5Z?9vc0#3F4YRq9AP``*m# z%-e6?%={7v_!*$WW?TGEfnoljn+AF6i-UJzQD6{**aS0Ed$Thv@_fV0cn}AiLp*RE z3BZL_HX`oQPp9YEx(E8=;o;ypAixTY$;4mQf{YRZuTSf7nvfNmU)@kW~qdvrFCW(pALccnMA= zqVw1h^i(2dLdfz zwoDIj!1xjKSg?5GC}VM&?Itq$hL^avNd?=dbrEEWn?4LuDAap{stc}4=+U0=E*OqP z@K?)Nhg@(A*l_r`p46TQgx+JKP!^yp2+ZLiPcKqKLR1!jk7nJpqNouiZ-I=;^((+K z%udg_(yHAvSm94*CbKwyvl{5kew^1zw@TO72iI?|Pn7*bneiRDeQhi^R^)8CXG`v@ z$bGilU*`KsD|mSYR1pL&s3t7l6ja1L7XLF?`DxM)XK=AhOX_@bX(?vtq=U*%0BZ(H zra(2UdcYt|jmClf8<;lEm;E2S2~ZL^c7eJH)%gDbWeJG4L{o^Q3 z4YlAky~kRLjk}J#ci#tq*#{?HV<{nD!>1*gQry=R6t>9U@TRj5#+oY+$)*JL=e2zQ zP=CIL7t3$@<8I%7H5O9pXVpOeH#KU>rhM#Q2aX~rrUGaE)}XcMQk)iK6PZfGK2GbV ziBJ%Qer!3yCSZyNy}vG*fp}+Q{o>u|Aq}r-h;E4we&ZQaguc@HashPH?yDLEV_jW} z#>j>6=uQTQr%K?fDd2O7JDK? zq_bvZ*zwJc3?p0<)!$qKYxOw+(+TU5;BgI*&?)Hfw9z@Tku;(SI#jUk@ONSfO#0l| zbmmN-6l<2J^As`S>vA)RK=oo`31)=h)8CV_CxF&PHCQ}E~)V0s+WC-y`p7;b8) z7e6Wcr(e@5U}&|qXKqwmIttQ5sTeM`*)3=HnJ(eIEMJvFYooc*{Dduc7wo?vE;Es{a^!oD`ypN{Tk{AHH7c#&Ce9SUdQX7Z(P|x8@GSDw23xvm)obZ z(vH%xHkF$yp0JfOS+*)GYnOAEi{sDaUh27{voP^+;=9SLuiDmK7R=R!|Dz0qx4pw>x?cO1~d$^(u z=Wgt&@FRN{8KtYthuzr`5o>qjJYZP6Ds(^*+J0SZpD?bO3;v-rwvD%NZkDmmZ{`=iy#rPyNnyhKu~c{hi;wzt8>s&OPV1&n}k( zfh~M;Pjzz${bWB53|E5EF$flrgdU>XNW$Rp3>W012YH6M;NjsZ{Q?Ipo<&oK^Pn=5 zIEi0}KFnSs$#MiGR8iI=C|e92)cS9)nyM=HBdR#6sM;eaXBFjIt{p+ay0Gqs@1V;x zOW)HC@Y{5YZuSKXOHxb_ot?*z%nQ8{RtJ4WKhmw-{XP`9;Wnpqq3%H@{El zDXBt~u_K5Leu8MQSU?q3c0qyiP-s$4kPw-WmC!^?BVt5Mit(AdM2V=eL@G`qNjYL} zqLQwtVk#9%iHb^;GpQM)-V7rONy(8|a$Hu}2eAg~BXAkC>u6uRxiY#mx;nl_^8RzQ z{d^JO9)H1q!c-I4TX}y!Z65%2&{OcVEu`nutF|?F-qZQj)0OjdWj$LRdCz6qas`m9 z*jMoRSG-H!)y}Mt_w`Wk1(18&3T?+%dY5`vZ)7|2ZN0Sh;+DH;x7Y`Zyj8H4U@NF< zZUqp`xs5}xfV96eyUtLsdoamE=#C#E&W>jB6r=yKSx&+}&?L_EJoD?7N*K)@x4?TN z=p-D+7@9kk=Eu-94qC#7H7X|(G0m`wx;7~*3M(Dt3|=Lg!Hbd<LYkU%sU@`Ynt{F(kk{&0Q6fbDz{j", self.clear_placeholder) + self.repo_entry.bind("", lambda event: self.analyze()) + + analyze_button = tk.Button( + input_frame, + text="Анализировать", + command=self.analyze, + bg="#4d8ee8", + fg="white", + font=("Arial", 11, "bold"), + relief="flat", + padx=20, + pady=7, + cursor="hand2", + ) + analyze_button.pack(side="left", padx=(10, 0)) + + self.result_text = tk.Text( + self.root, + font=("Consolas", 11), + wrap="word", + state="disabled", + bg="#ffffff", + fg="#111111", + ) + self.result_text.pack(fill="both", expand=True, padx=30, pady=20) + + def clear_placeholder(self, event): + if self.repo_entry.get() == "https://iux-gitea.myddns.me/owner/repo": + self.repo_entry.delete(0, tk.END) + + def set_text(self, text): + self.result_text.config(state="normal") + self.result_text.delete("1.0", tk.END) + self.result_text.insert(tk.END, text) + self.result_text.config(state="disabled") + + def analyze(self): + repo_link = self.repo_entry.get().strip() + + if not repo_link or repo_link == "https://iux-gitea.myddns.me/owner/repo": + messagebox.showerror("Ошибка", "Введите ссылку на репозиторий") + return + + try: + self.set_text("Загрузка данных...\n") + self.root.update() + + repo_data = get_repo_data(repo_link) + commits = get_commits(repo_link) + lines = get_code_lines(repo_link) + + info = parse_repo_info(repo_data) + authors = parse_authors(commits) + + output = [] + output.append(f"Ссылка: {repo_link}\n") + output.append(info) + output.append("\nАвторы / соавторы по коммитам:\n") + + if authors: + for author in sorted(authors): + output.append(f"- {author}\n") + else: + output.append("- нет данных\n") + + output.append(f"\nСтрок Python-кода: {lines}\n") + + self.set_text("".join(output)) + + except Exception as error: + self.set_text("") + messagebox.showerror("Ошибка", f"Не удалось получить данные:\n{error}") + + +if __name__ == "__main__": + GiteaAnalyzer() diff --git a/alpha/gitea_simple_app/parser.py b/alpha/gitea_simple_app/parser.py new file mode 100644 index 0000000..53afaee --- /dev/null +++ b/alpha/gitea_simple_app/parser.py @@ -0,0 +1,20 @@ +def parse_repo_info(data): + return ( + f"Название: {data.get('name', '—')}\n" + f"Описание: {data.get('description', '—')}\n" + f"Автор: {data.get('owner', {}).get('login', '—')}\n" + f"Создан: {data.get('created_at', '—')}\n" + f"Изменён: {data.get('updated_at', '—')}\n" + ) + + +def parse_authors(commits): + authors = set() + + for commit in commits: + try: + authors.add(commit["commit"]["author"]["name"]) + except: + continue + + return authors \ No newline at end of file diff --git a/alpha/gitea_simple_app/requirements.txt b/alpha/gitea_simple_app/requirements.txt new file mode 100644 index 0000000..663bd1f --- /dev/null +++ b/alpha/gitea_simple_app/requirements.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/alpha/gitea_simple_app/run_linux.sh b/alpha/gitea_simple_app/run_linux.sh new file mode 100755 index 0000000..30e69fa --- /dev/null +++ b/alpha/gitea_simple_app/run_linux.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" +python3 main.py diff --git a/alpha/gitea_simple_app/run_windows.bat b/alpha/gitea_simple_app/run_windows.bat new file mode 100644 index 0000000..481baa4 --- /dev/null +++ b/alpha/gitea_simple_app/run_windows.bat @@ -0,0 +1,4 @@ +@echo off +cd /d "%~dp0" +python main.py +pause diff --git a/beta1/gitea_analyzer_app/README.md b/beta1/gitea_analyzer_app/README.md new file mode 100644 index 0000000..a2bdb65 --- /dev/null +++ b/beta1/gitea_analyzer_app/README.md @@ -0,0 +1,46 @@ +# Gitea Repository Analyzer + +Программа с графическим интерфейсом для анализа репозиториев Gitea. + +## Что умеет программа + +- заставка при запуске; +- регистрация профиля; +- вход по логину и паролю; +- сохранение ссылок на репозитории для каждого пользователя; +- обновление информации по выбранной ссылке отдельной кнопкой; +- вывод автора, соавторов, даты создания, даты изменения; +- подсчёт строк Python-кода. + +## Запуск через Python + +```bash +pip install -r requirements.txt +python main.py +``` + +## Сборка в EXE + +На Windows открой папку проекта и запусти файл: + +```text +build_exe.bat +``` + +После сборки файл появится здесь: + +```text +dist/GiteaAnalyzer.exe +``` + +Его можно перенести на рабочий стол и запускать как обычную программу. + +## Где хранятся аккаунты и ссылки + +Данные сохраняются на компьютере пользователя в папке: + +```text +C:\Users\USERNAME\GiteaAnalyzer\users.json +``` + +Пароли хранятся не обычным текстом, а в виде SHA-256 хеша. diff --git a/beta1/gitea_analyzer_app/__pycache__/api.cpython-312.pyc b/beta1/gitea_analyzer_app/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..166febe0c4600da34aad9277182de030e16a737c GIT binary patch literal 3828 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 Ucs;bj_`Tr6%JQZFj(Y{40pi3!;{X5v literal 0 HcmV?d00001 diff --git a/beta1/gitea_analyzer_app/__pycache__/storage.cpython-312.pyc b/beta1/gitea_analyzer_app/__pycache__/storage.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f07fb2a9fd5fdfab199a1af7ce12bf5072bad54c GIT binary patch literal 3626 zcmcgvUrbxq89(R#v3-4Q41@%ds4ESP;4TTQ$x=cRk`e`~t`UkFrYgKx9{0xB7~4Ac z5}(op<@8w!%i+97rr1hn5Dd|*+Nz=aXTwmLC zuuht^gZ!QEp7Wi5zwh^b=kUjHI7pxz{76Zj@DuVk{P2ogQJ#Jc$|BK;PE%ymt?4M` z-@>S1(4@~BQmd0nP4~22ELE?+R_nqFb-#3RMR2uI-!9{KTFIwN)p34ZzC}g@x(}qH z`#}cv07z9=K!)@n$gr-0Y|uj>BYGHQ<1E!0zQm=6x9FQr_~nFU#0Ju_)a)Audm}hy z8qDlYnwj*NyFFJ*P>Jw+dK$zcu_~t^Bw0CyYvxJ|t$ESuJ;B>AC9^~mhetH(1dN%4 zX+<*=n&=1_(+Nz*CJa5nOvgWP`EvB)E3e%pPjQ03Uk1@Lo|!ayjCh9i*o*e6{p;df z@h$sP`!oANPaJn2ja9ZEjb*d#UB|T@ntMzu!(wrxJ3H${qDI=BVg{N=VObW2RS<2n z5yTwXkbFOVb^g_N{mak)S?Xly$8BIBEjSqe1f?E~75K(NiB*LqSp~!GLzx6he!Ex! zuf?N?DI~}h*q2o$Qq4xEx^Pci!CgQ(Np27e55Y^a!P9DWj(D?<2|#f8tGVS0=^!r< zlTHhiT!p=(qh`dbWSVvm3lZVvdBS8$5@bxc3cH%FSZLC)L)n%*WnDXV>MnXVJ(kfE z>A0qFR2iPsk+Lys-0^X*gO4v>hz`ASY0!}}StIR8NH#}GWn#Lc49<)hSu2rA152c9 ziIia?)7n`GrwO7>lrxkaga$mZiJn21?OB)hZm8jf-hA)Ex%|2JJJ;1i7&uGrUv1e4gcg*%QaHTSa%b?tbAJk)1)s_N;4``Z zD->HMM#(P^3=naR$ODRh8~B*=Ir!H=sRw_j^pzt??}`9xujtf^Ag|sjioFbQ1wb3- zIBJsPACH;isl-nlpE({oe)2_#1dI~HQO1oKJrOrd3zK3tW}4F(rq@$Gj6+^>ElEf-WPIUbryQ8DpI-X)du-PguI{$LsRF$#QqiJ?9c3n z_V3#5KS1^S;@gnCAKIVTtHqo4ef(~ReEwVeetU7g_*OA*--r69{RuSQFW%Gyrok*u zh#A?8nSd;wFicGtnZgWUe^8vW9~N)f58P?yVct*e-@t;OYa-7P95RM*!CfP#GVw&3 z&&LiylZoeR_jnm*MjWmsgK=)MZs_AiFMdDY0U}3kPeC#&tKI(&KZX;Be+HCY;1`lr*ukh$Y6<*?m=jHK zPEOp(uJ*#Hb4}HG6I}$7H{8NQ9E1u+juH^wGh zl#W9WB4utzNo`!{%l8$2Tv89tUHpq0DMwn$YGmP5{#4;dCH2`4`&Zja9jA-xXZGkJyig%@9hNz4T0UHn(Cuka$Zd{8^r7Xt>ZzdzH^N70Z zvc*vlmS`%Gp5RgC$Q&kfJ82qXx?aO?mSOfd13z;BL=C-AQ{iy_(xXsEG33G)>cyaI zT#}3aXUc)_LMR_9TwM=5yAfzEoLmp=FGu#2)yDq^uH=8il_6Iukg{IT9Un6$GuI7{ zCF?^hwnNsW8!5vw>QTdlI*6A49cqQaqJRH)pr$qPYn#8+*kPEP?EwMLvP>fF1dW+& zEUjY_VE96IuX%iUxgmpz)lIRO1Q=!m9v9rb40p@$A2IG8{)pQOoSn?*Qz_#dy8s;+ z^`;2|URjhrChB9NJSGi)4Tcsv^PLMv^G6G8ar&L