Compare commits

..

8 Commits

Author SHA1 Message Date
zsyg
0137e43408 添加视频压缩代码 2025-06-28 16:10:13 +08:00
zsyg
3f88a5e5c7 上传视频压缩软件图标 2025-06-28 16:10:11 +08:00
zsyg
ba7ed20664 添加视频压缩程序 2025-06-28 16:09:12 +08:00
zsyg
336b3d3ed9 Add files via upload 2025-06-28 16:08:38 +08:00
zsyg
214a179923 Add files via upload 2025-06-28 13:23:21 +08:00
zsyg
fad8522b88 添加英文README.md 2025-06-28 12:11:31 +08:00
zsyg
337c1853c7 Create CODE_OF_CONDUCT.md 2025-06-28 12:07:38 +08:00
zsyg
cdb54b95c2 Update README.md 2025-06-28 12:04:37 +08:00
30 changed files with 2057 additions and 3 deletions

View File

@@ -50,7 +50,7 @@ namespace AppStore
// 初始化并添加应用信息 // 初始化并添加应用信息
infoLabel = new Label(); infoLabel = new Label();
infoLabel.Text = "kortapp-z\n版本: 1.0.6\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C++的软件"; infoLabel.Text = "kortapp-z\n版本: 1.0.7\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
infoLabel.Font = new Font("Microsoft YaHei", 12); infoLabel.Font = new Font("Microsoft YaHei", 12);
infoLabel.AutoSize = false; infoLabel.AutoSize = false;
infoLabel.Width = 300; infoLabel.Width = 300;

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, 和 experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, 和 sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, 和 personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
3872006562.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -267,8 +267,13 @@ namespace AppStore
var flowPanel = new FlowLayoutPanel(); var flowPanel = new FlowLayoutPanel();
flowPanel.Dock = DockStyle.Fill; flowPanel.Dock = DockStyle.Fill;
flowPanel.AutoScroll = true; flowPanel.AutoScroll = true;
flowPanel.WrapContents = false; flowPanel.WrapContents = true;
flowPanel.FlowDirection = FlowDirection.LeftToRight; flowPanel.FlowDirection = FlowDirection.LeftToRight;
flowPanel.Padding = new Padding(15, 50, 15, 15);
flowPanel.Margin = new Padding(0);
flowPanel.AutoSize = true;
flowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
flowPanel.AutoScrollMinSize = new Size(0, 3350);
contentPanel.Controls.Add(flowPanel); contentPanel.Controls.Add(flowPanel);
// 系统清理卡片 // 系统清理卡片
@@ -441,6 +446,44 @@ namespace AppStore
}; };
flowPanel.Controls.Add(systemInfoCard); flowPanel.Controls.Add(systemInfoCard);
// 视频压缩工具卡片
var videoCompressorCard = new ToolCard();
videoCompressorCard.ToolName = "视频压缩工具";
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "video_compressor.png");
if (File.Exists(iconPath))
{
videoCompressorCard.ToolIcon = Image.FromFile(iconPath);
}
else
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
}
catch
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
videoCompressorCard.UpdateDisplay();
videoCompressorCard.ToolCardClicked += (s, e) => {
try {
string toolPath = Path.Combine(Application.StartupPath, "resource", "video_compressor.exe");
if (File.Exists(toolPath)) {
Process.Start(toolPath);
} else {
MessageBox.Show("视频压缩工具未找到,请确保已正确安装", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
} catch (Exception ex) {
MessageBox.Show($"启动视频压缩工具失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
flowPanel.Controls.Add(videoCompressorCard);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -82,7 +82,7 @@ Copyright (c) 2025 zsyg
## 其他网站 ## 其他网站
gitee镜像仓库:https://gitee.com/chr_super/kortapp-z(目前已经停止维护) gitee镜像仓库:https://gitee.com/chr_super/kortapp-z (目前已经停止维护)
## 维护 ## 维护

135
README/de-DE_README.md Normal file
View File

@@ -0,0 +1,135 @@
# Kortapp-z - Windows App Store
**Open-Source, kostenlos, werbefrei**
Grundsatz: Keine Werbung, kontinuierliche Updates
## Open-Source-Richtlinien
1. **Open-Source-Code**: Nutzung, Modifikation, Verbreitung und kommerzielle Nutzung erlaubt, mit Pflicht zur Nennung des Originalautors.
2. **Open-Source-Dokumentation**: Gleiche Bedingungen wie für Code.
3. **Open-Source-Ressourcen** (Icons, Screenshots): Gleiche Bedingungen.
4. Alle abgeleiteten Produkte (Websites, Apps, Erweiterungen etc.) müssen diese Lizenz einhalten.
5. **Keine Werbung** in keiner Form.
6. **Keine Spenden** werden angenommen.
7. **Keine Sponsoring** wird angenommen.
8. **Pull Requests (PR) sind willkommen**, auch ohne vorheriges Issue.
9. Eigene Projekte können per PR eingereicht werden, aber solche mit unter **1000 Stars** werden gelöscht.
## Projektbeschreibung
Eine einfache Windows-App zum Herunterladen und Verwalten von Software.
**Hauptfunktionen:**
- Softwareverwaltung
- Download-Manager
- Integrierte Tools
## Hauptmerkmale
- Minimalistische Download-Oberfläche
- Download-Fortschrittsverfolgung
- Hintergrund-Downloads
- Visuell ansprechende App-Karten
- Sauberer und strukturierter Code
## Build und Packaging
### Systemanforderungen
- **.NET 8.0 SDK**
- **Windows 10/11**
### Build-Befehle
#### 32-Bit-Version
```bash
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
```
#### 64-Bit-Version
```bash
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
```
Erstellte Dateien werden unter folgendem Pfad abgelegt:
```
bin\Release\net8.0-windows\[Plattform]\publish
```
### Zusätzliche Optionen
- `--self-contained true` eigenständige Builds (größere Dateien)
- `-p:PublishTrimmed=true` Größenreduzierung (experimentell)
## Projektstruktur
```
kortapp-z/
├── MainForm.cs # Hauptfenster-Logik
├── DownloadManager.cs # Download-Manager
├── AppCard.cs # App-Karte
├── DownloadItem.cs # Download-Element
├── img/ # Grafiken
│ ├── ico/ # Icons
│ └── png/ # Screenshots
└── resource/ # Ressourcen
└── aria2c.exe # Download-Tool
```
## Laufzeitanforderungen
- **.NET 8.0 Runtime** (bei Framework-abhängiger Build)
- **Windows 10 oder neuer**
## Lizenz
**MIT License**
Copyright (c) 2025 zsyg
## Andere Plattformen
**Gitee-Mirror**: [https://gitee.com/chr_super/kortapp-z](https://gitee.com/chr_super/kortapp-z) (nicht mehr gewartet)
## Wartung
Der Gitee-Repository wird nicht mehr synchronisiert. Hilfe beim Mirroring ist willkommen:
- **QQ**: 3872006562
- **Bilibili (Direktnachricht)**: Zayisynth
**Wichtig:**
- Aufgrund eines Konflikts mit Daye wird **windowscleaner** nie hinzugefügt.
- Benennen Sie `img/png/NET.png` in `.NET.png` um, um Fehler zu vermeiden (GitHub-Beschränkungen).
## Mitwirken
Jeder kann legale Software per Pull Request vorschlagen.
## Kontakt
📧 **Email**:
```
3872006562@qq.com
```
📱 **QQ**:
```
3872006562
```
👥 **QQ-Gruppe**:
```
1043867176
```
🎥 **Bilibili**:
```
Zayisynth
```
---
### Wie sollte die deutsche README benannt werden?
Empfohlene Optionen:
1. **de-DE_README.md** (IETF-Standard)
2. **README_de.md** (kürzere Variante)
3. **DE_README.md** (explizite Sprachkennung)
Am besten halten Sie sich an das Format `[Sprachcode]_README.md`, wie bei anderen Übersetzungen.

123
README/fr-FR_README.md Normal file
View File

@@ -0,0 +1,123 @@
# Kortapp-z - Microsoft Store -- Logiciel open source, gratuit et sans publicité
Engagement : aucune publicité acceptée, mises à jour continues
## Politique open source
1. Code open source : utilisation, modification, distribution et usage commercial autorisés, avec mention de l'auteur original obligatoire.
2. Documentation open source : mêmes conditions que le code.
3. Ressources graphiques (icônes, captures d'écran) open source : mêmes conditions.
4. Tout produit dérivé (sites web, apps, extensions...) doit respecter cette licence.
5. Aucune publicité n'est acceptée, sous aucune forme.
6. Aucun don n'est accepté.
7. Aucun sponsoring n'est accepté.
8. Les Pull Requests (PR) sont bienvenues, même sans issue préalable.
9. Vous pouvez soumettre vos projets via PR, mais ceux avec moins de 1k stars seront supprimés.
## Présentation
Une application simple de boutique Windows pour télécharger et gérer des logiciels.
Fonctionnalités :
- Gestion de logiciels
- Gestion de téléchargements
- Outils intégrés
## Fonctionnalités clés
- Interface épurée pour le téléchargement
- Gestion de la progression des téléchargements
- Téléchargements en arrière-plan
- Présentation sous forme de cartes visuelles
- Code structuré et modulaire
## Compilation et packaging
### Prérequis
- SDK .NET 8.0
- Windows 10/11
### Commandes
#### Version 32-bit
```bash
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
```
#### Version 64-bit
```bash
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
```
Fichiers générés :
```
bin\Release\net8.0-windows\[platform]\publish
```
### Options avancées
- `--self-contained true` : package autonome (taille plus importante)
- `-p:PublishTrimmed=true` : réduction de taille (expérimental)
## Structure du projet
```
kortapp-z/
├── MainForm.cs # Logique de la fenêtre principale
├── DownloadManager.cs # Gestion des téléchargements
├── AppCard.cs # Contrôle des cartes d'applications
├── DownloadItem.cs # Contrôle des éléments de téléchargement
├── img/ # Ressources visuelles
│ ├── ico/ # Icônes
│ └── png/ # Captures d'écran
└── resource/ # Fichiers ressources
└── aria2c.exe # Outil de téléchargement
```
## Prérequis d'exécution
- Runtime .NET 8.0 (si version dépendante du framework)
- Windows 10 ou supérieur
## Licence
MIT License
Copyright (c) 2025 zsyg
## Autres plateformes
Dépôt miroir Gitee : https://gitee.com/chr_super/kortapp-z (maintenance arrêtée)
## Maintenance
Le dépôt Gitee n'étant plus maintenu par manque d'utilisation, toute aide pour la synchronisation est bienvenue.
Contact : QQ 3872006562 ou message privé sur Bilibili (mention dans le README en remerciement).
Note : Suite à un conflit avec Daye, l'application windowscleaner ne sera jamais publiée ici.
Important : Renommez `img/png/NET.png` en `.NET.png` pour éviter des problèmes (limitations GitHub).
## Contributions
Tout utilisateur peut ajouter des logiciels légaux via PR.
## Contacts
Email :
```
3872006562@qq.com
```
QQ :
```
3872006562
```
Groupe QQ :
```
1043867176
```
Compte Bilibili :
```
Zayisynth
```

135
README/ru-RU_README.md Normal file
View File

@@ -0,0 +1,135 @@
# Kortapp-z — Магазин приложений Windows
**Открытое ПО, бесплатно, без рекламы**
Обещание: никакой рекламы, постоянные обновления
## Политика открытого кода
1. **Открытый исходный код**: можно использовать, изменять, распространять и применять в коммерческих целях с обязательным указанием автора.
2. **Открытая документация**: те же условия, что и для кода.
3. **Открытые ресурсы** (иконки, скриншоты): те же условия.
4. Все производные продукты (сайты, приложения, расширения и т. д.) должны соблюдать эту лицензию.
5. **Никакой рекламы** — ни в какой форме.
6. **Не принимаются пожертвования**.
7. **Не принимается спонсорская поддержка**.
8. **Pull Requests (PR) приветствуются**, даже без предварительного issue.
9. Можно предлагать свои проекты через PR, но те, у которых меньше **1000 звёзд**, будут удалены.
## Описание проекта
Простое приложение для Windows, позволяющее скачивать и управлять программами.
**Основные функции:**
- Управление установленными приложениями
- Менеджер загрузок
- Встроенные инструменты
## Ключевые особенности
- Минималистичный интерфейс загрузки
- Отслеживание прогресса загрузки
- Фоновые загрузки
- Красивые карточки приложений
- Чистый и структурированный код
## Сборка и упаковка
### Системные требования
- **.NET 8.0 SDK**
- **Windows 10/11**
### Команды сборки
#### 32-битная версия
```bash
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
```
#### 64-битная версия
```bash
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
```
Собранные файлы появятся в:
```
bin\Release\net8.0-windows\[платформа]\publish
```
### Дополнительные опции
- `--self-contained true` — автономная сборка (больший размер)
- `-p:PublishTrimmed=true` — уменьшение размера (экспериментально)
## Структура проекта
```
kortapp-z/
├── MainForm.cs # Логика главного окна
├── DownloadManager.cs # Менеджер загрузок
├── AppCard.cs # Карточка приложения
├── DownloadItem.cs # Элемент загрузки
├── img/ # Графика
│ ├── ico/ # Иконки
│ └── png/ # Скриншоты
└── resource/ # Ресурсы
└── aria2c.exe # Утилита загрузки
```
## Требования для запуска
- **.NET 8.0 Runtime** (если используется зависимая сборка)
- **Windows 10 или новее**
## Лицензия
**MIT License**
Copyright (c) 2025 zsyg
## Другие платформы
**Зеркало на Gitee**: [https://gitee.com/chr_super/kortapp-z](https://gitee.com/chr_super/kortapp-z) (поддержка прекращена)
## Поддержка
Репозиторий на Gitee больше не синхронизируется. Если кто-то может помочь с зеркалированием — пишите:
- **QQ**: 3872006562
- **Bilibili (личные сообщения)**: Zayisynth
**Важно**:
- Из-за конфликта с Daye приложение **windowscleaner** никогда не будет добавлено.
- Переименуйте `img/png/NET.png` в `.NET.png`, иначе возможны ошибки (ограничения GitHub).
## Участие
Любой может предложить легальное ПО через Pull Request.
## Контакты
📧 **Email**:
```
3872006562@qq.com
```
📱 **QQ**:
```
3872006562
```
👥 **QQ-группа**:
```
1043867176
```
🎥 **Bilibili**:
```
Zayisynth
```
---
### Как назвать файл README на русском?
Рекомендуемые варианты:
1. **ru-RU_README.md** (стандартный IETF-код)
2. **README_ru.md** (более короткий вариант)
3. **RUS_README.md** (если предпочитаете явное обозначение)
Лучше всего придерживаться формата `[язык]_README.md`, как в других переводах.

115
en-US_README.md Normal file
View File

@@ -0,0 +1,115 @@
# Kortapp-z - Windows App Store -- Advocating for Open Source, Free Software, and No Ads
Setting a small flag: Never accept ads, continuously update.
## Open Source Practices
1. The project code is open source, allowing anyone to use, modify, distribute, or commercialize it, but the original author must be credited.
2. The project documentation is open source, allowing anyone to use, modify, distribute, or commercialize it, but the original author must be credited.
3. Project resources such as icons and screenshots are open source, allowing anyone to use, modify, distribute, or commercialize them, but the original author must be credited.
4. Any derivatives of the project (including but not limited to websites, apps, plugins, etc.) must adhere to the above open-source license.
5. The project does not accept any form of advertising, and ads must not be placed anywhere.
6. The project does not accept any form of donations.
7. The project does not accept any form of sponsorship.
8. The project welcomes PRs (Pull Requests) in any form. Submitting issues is not required.
9. You can submit PRs for your own projects. However, if the star count is below 1k, they will be deleted.
## Project Overview
A simple Windows app store application that provides software download and management features.
Offers software management, download management, built-in tools, and more.
## Features
- Clean software download interface
- Download progress management
- Supports background downloads
- Beautiful app card display
- Functional and structured code handling
## Build and Packaging
### System Requirements
- .NET 8.0 SDK
- Windows 10/11
### Packaging Commands
#### 32-bit Version
```bash
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
```
#### 64-bit Version
```bash
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
```
The packaged executable will include the specified application icon and be output to:
```
bin\Release\net8.0-windows\[platform]\publish
```
### Advanced Options
- Add `--self-contained true` to generate a standalone package (larger size).
- Add `-p:PublishTrimmed=true` to reduce package size (experimental).
## Project Structure
```
kortapp-z/
├── MainForm.cs # Main form logic
├── DownloadManager.cs # Download management
├── AppCard.cs # App card control
├── DownloadItem.cs # Download item control
├── img/ # Image resources
│ ├── ico/ # Icon files
│ └── png/ # App screenshots
└── resource/ # Resource files
└── aria2c.exe # Download tool
```
## Runtime Requirements
- .NET 8.0 runtime (if using framework-dependent deployment)
- Windows 10 or later
## License
MIT License
Copyright (c) 2025 zsyg
## Other Websites
Gitee Mirror Repository: https://gitee.com/chr_super/kortapp-z (Currently no longer maintained)
## Maintenance
Since I rarely use Gitee and find it cumbersome to operate, the Gitee mirror will no longer be synced. If anyone knows how to set up a mirror, please help. Contact me via QQ: 3872006562 or DM me on Bilibili. I will acknowledge your help in the README. Thank you!
Due to a conflict with Daye, Windowscleaner will never be listed. I will strive on my own.
Note: Due to GitHub file upload restrictions, rename `img/png/NET.png` to `.NET.png`; otherwise, the program may encounter unexpected issues.
Anyone can add their own legal software via PR.
Author's Email:
```
3872006562@qq.com
```
Author's QQ:
```
3872006562
```
QQ Group:
```
1043867176
```
Bilibili Account:
```
Zayisynth
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 KiB

View File

@@ -0,0 +1,34 @@
# 编译器设置
CC = gcc
CFLAGS = -Wall -Wextra -O2 -Iinclude
LDFLAGS = -lavcodec -lavformat -lavutil -lswscale -lgdi32 -lcomdlg32 -mwindows
# 目录设置
OBJ_DIR = obj
BUILD_DIR = build
# 源文件和目标文件
SRC = $(wildcard src/*.c)
OBJ = $(patsubst src/%.c,$(OBJ_DIR)/%.o,$(SRC))
EXEC = $(BUILD_DIR)/video_compressor.exe
# 创建目录
$(shell mkdir -p $(OBJ_DIR))
$(shell mkdir -p $(BUILD_DIR))
# 默认目标
all: $(EXEC)
# 链接可执行文件
$(EXEC): $(OBJ)
$(CC) -o $@ $^ $(LDFLAGS)
# 编译规则
$(OBJ_DIR)/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $@
# 清理规则
clean:
del /Q $(OBJ_DIR)\*.o $(EXEC)
.PHONY: all clean

View File

@@ -0,0 +1,65 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <stdbool.h>
/**
* 加载配置文件
* @param config_file 配置文件路径
* @return true表示成功false表示失败
*/
bool config_load(const char* config_file);
/**
* 保存配置文件
* @param config_file 配置文件路径
* @return true表示成功false表示失败
*/
bool config_save(const char* config_file);
/**
* 获取字符串配置值
* @param key 配置键
* @param default_value 默认值
* @return 配置值
*/
const char* config_get_string(const char* key, const char* default_value);
/**
* 获取整数配置值
* @param key 配置键
* @param default_value 默认值
* @return 配置值
*/
int config_get_int(const char* key, int default_value);
/**
* 获取布尔配置值
* @param key 配置键
* @param default_value 默认值
* @return 配置值
*/
bool config_get_bool(const char* key, bool default_value);
/**
* 设置字符串配置值
* @param key 配置键
* @param value 配置值
*/
void config_set_string(const char* key, const char* value);
/**
* 设置整数配置值
* @param key 配置键
* @param value 配置值
*/
void config_set_int(const char* key, int value);
/**
* 设置布尔配置值
* @param key 配置键
* @param value 配置值
*/
void config_set_bool(const char* key, bool value);
#endif // CONFIG_H

View File

@@ -0,0 +1,37 @@
#ifndef ERROR_H
#define ERROR_H
typedef enum {
ERR_NONE = 0,
ERR_FILE_NOT_FOUND,
ERR_INVALID_ARGUMENT,
ERR_MEMORY_ALLOC,
ERR_FFMPEG,
ERR_UNKNOWN
} ErrorCode;
/**
* 设置当前错误代码
* @param code 错误代码
* @param message 错误信息(可选)
*/
void error_set(ErrorCode code, const char* message);
/**
* 获取当前错误代码
* @return 错误代码
*/
ErrorCode error_get_code();
/**
* 获取当前错误信息
* @return 错误信息字符串
*/
const char* error_get_message();
/**
* 清除错误状态
*/
void error_clear();
#endif // ERROR_H

View File

@@ -0,0 +1,27 @@
#ifndef FILE_UTILS_H
#define FILE_UTILS_H
#include <stdbool.h>
/**
* 检查文件是否存在
* @param path 文件路径
* @return true表示存在false表示不存在
*/
bool file_exists(const char* path);
/**
* 获取文件大小
* @param path 文件路径
* @return 文件大小(字节)-1表示错误
*/
long file_size(const char* path);
/**
* 获取文件扩展名
* @param path 文件路径
* @return 扩展名字符串(包含.)NULL表示没有扩展名
*/
const char* file_extension(const char* path);
#endif // FILE_UTILS_H

View File

@@ -0,0 +1,16 @@
#ifndef GUI_H
#define GUI_H
#include <windows.h>
// 初始化GUI界面
BOOL init_gui(HINSTANCE hInstance);
// 主窗口过程函数
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam);
// 创建压缩参数设置控件
void create_compression_controls(HWND hwnd);
#endif // GUI_H

View File

@@ -0,0 +1,38 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <stdio.h>
typedef enum {
LOG_DEBUG,
LOG_INFO,
LOG_WARNING,
LOG_ERROR
} LogLevel;
/**
* 初始化日志系统
* @param log_file 日志文件路径NULL表示输出到stdout
*/
void logger_init(const char* log_file);
/**
* 设置日志级别
* @param level 日志级别
*/
void logger_set_level(LogLevel level);
/**
* 记录日志
* @param level 日志级别
* @param format 格式化字符串
* @param ... 可变参数
*/
void logger_log(LogLevel level, const char* format, ...);
/**
* 关闭日志系统
*/
void logger_close();
#endif // LOGGER_H

View File

@@ -0,0 +1,21 @@
#ifndef PROGRESS_H
#define PROGRESS_H
/**
* 初始化进度显示
* @param total 总工作量
*/
void progress_init(long total);
/**
* 更新进度
* @param current 当前进度
*/
void progress_update(long current);
/**
* 完成进度显示
*/
void progress_finish();
#endif // PROGRESS_H

View File

@@ -0,0 +1,61 @@
#ifndef STRING_UTILS_H
#define STRING_UTILS_H
#include <stddef.h>
/**
* 安全的字符串拷贝
* @param dest 目标缓冲区
* @param src 源字符串
* @param dest_size 目标缓冲区大小
* @return 目标字符串
*/
char* str_copy(char* dest, const char* src, size_t dest_size);
/**
* 安全的字符串连接
* @param dest 目标缓冲区
* @param src 要连接的字符串
* @param dest_size 目标缓冲区大小
* @return 目标字符串
*/
char* str_concat(char* dest, const char* src, size_t dest_size);
/**
* 去除字符串两端的空白字符
* @param str 要处理的字符串
* @return 处理后的字符串
*/
char* str_trim(char* str);
/**
* 检查字符串是否以指定前缀开头
* @param str 要检查的字符串
* @param prefix 前缀
* @return 1表示是0表示否
*/
int str_starts_with(const char* str, const char* prefix);
/**
* 检查字符串是否以指定后缀结尾
* @param str 要检查的字符串
* @param suffix 后缀
* @return 1表示是0表示否
*/
int str_ends_with(const char* str, const char* suffix);
/**
* 将字符串转换为小写
* @param str 要转换的字符串
* @return 转换后的字符串
*/
char* str_to_lower(char* str);
/**
* 将字符串转换为大写
* @param str 要转换的字符串
* @return 转换后的字符串
*/
char* str_to_upper(char* str);
#endif // STRING_UTILS_H

View File

@@ -0,0 +1,26 @@
#ifndef UTILS_H
#define UTILS_H
#include <stdbool.h>
/**
* 获取当前时间戳(毫秒)
* @return 时间戳
*/
long long get_timestamp();
/**
* 生成随机字符串
* @param buffer 输出缓冲区
* @param length 字符串长度
*/
void generate_random_string(char* buffer, int length);
/**
* 检查指针是否有效
* @param ptr 要检查的指针
* @return true表示有效false表示无效
*/
bool is_pointer_valid(const void* ptr);
#endif // UTILS_H

View File

@@ -0,0 +1,24 @@
#ifndef VIDEO_COMPRESSOR_H
#define VIDEO_COMPRESSOR_H
/**
* 压缩视频文件
* @param input_file 输入文件路径
* @param output_file 输出文件路径
* @param quality 压缩质量(1-10000)
* @return 0表示成功非0表示失败
*/
int compress_video(const char* input_file, const char* output_file, int quality);
/**
* 初始化视频压缩模块
* @return 0表示成功非0表示失败
*/
int init_video_compressor();
/**
* 清理视频压缩模块资源
*/
void cleanup_video_compressor();
#endif // VIDEO_COMPRESSOR_H

View File

@@ -0,0 +1,127 @@
#include "config.h"
#include "string_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CONFIG_SIZE 1024
typedef struct ConfigEntry {
char* key;
char* value;
struct ConfigEntry* next;
} ConfigEntry;
static ConfigEntry* config_list = NULL;
static ConfigEntry* config_find_entry(const char* key) {
ConfigEntry* entry = config_list;
while (entry != NULL) {
if (strcmp(entry->key, key) == 0) {
return entry;
}
entry = entry->next;
}
return NULL;
}
bool config_load(const char* config_file) {
FILE* file = fopen(config_file, "r");
if (file == NULL) {
return false;
}
char line[MAX_CONFIG_SIZE];
while (fgets(line, sizeof(line), file) != NULL) {
// 去除注释和空白行
char* comment = strchr(line, '#');
if (comment != NULL) {
*comment = '\0';
}
str_trim(line);
if (strlen(line) == 0) {
continue;
}
// 解析键值对
char* separator = strchr(line, '=');
if (separator == NULL) {
continue;
}
*separator = '\0';
char* key = str_trim(line);
char* value = str_trim(separator + 1);
// 添加到配置列表
config_set_string(key, value);
}
fclose(file);
return true;
}
bool config_save(const char* config_file) {
FILE* file = fopen(config_file, "w");
if (file == NULL) {
return false;
}
ConfigEntry* entry = config_list;
while (entry != NULL) {
fprintf(file, "%s=%s\n", entry->key, entry->value);
entry = entry->next;
}
fclose(file);
return true;
}
const char* config_get_string(const char* key, const char* default_value) {
ConfigEntry* entry = config_find_entry(key);
if (entry != NULL) {
return entry->value;
}
return default_value;
}
int config_get_int(const char* key, int default_value) {
const char* str = config_get_string(key, NULL);
if (str != NULL) {
return atoi(str);
}
return default_value;
}
bool config_get_bool(const char* key, bool default_value) {
const char* str = config_get_string(key, NULL);
if (str != NULL) {
return strcmp(str, "true") == 0 || strcmp(str, "1") == 0;
}
return default_value;
}
void config_set_string(const char* key, const char* value) {
ConfigEntry* entry = config_find_entry(key);
if (entry != NULL) {
free(entry->value);
entry->value = strdup(value);
} else {
entry = malloc(sizeof(ConfigEntry));
entry->key = strdup(key);
entry->value = strdup(value);
entry->next = config_list;
config_list = entry;
}
}
void config_set_int(const char* key, int value) {
char str[32];
snprintf(str, sizeof(str), "%d", value);
config_set_string(key, str);
}
void config_set_bool(const char* key, bool value) {
config_set_string(key, value ? "true" : "false");
}

View File

@@ -0,0 +1,54 @@
#include "error.h"
#include "logger.h"
#include <string.h>
#include <stdlib.h>
static ErrorCode current_error = ERR_NONE;
static char* error_message = NULL;
void error_set(ErrorCode code, const char* message) {
current_error = code;
if (error_message != NULL) {
free(error_message);
error_message = NULL;
}
if (message != NULL) {
error_message = strdup(message);
}
// 记录错误日志
if (code != ERR_NONE) {
const char* error_name;
switch (code) {
case ERR_FILE_NOT_FOUND: error_name = "File not found"; break;
case ERR_INVALID_ARGUMENT: error_name = "Invalid argument"; break;
case ERR_MEMORY_ALLOC: error_name = "Memory allocation failed"; break;
case ERR_FFMPEG: error_name = "FFmpeg error"; break;
default: error_name = "Unknown error"; break;
}
if (message != NULL) {
logger_log(LOG_ERROR, "%s: %s", error_name, message);
} else {
logger_log(LOG_ERROR, "%s", error_name);
}
}
}
ErrorCode error_get_code() {
return current_error;
}
const char* error_get_message() {
return error_message;
}
void error_clear() {
current_error = ERR_NONE;
if (error_message != NULL) {
free(error_message);
error_message = NULL;
}
}

View File

@@ -0,0 +1,39 @@
#include "file_utils.h"
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
bool file_exists(const char* path) {
if (path == NULL) {
return false;
}
struct stat buffer;
return stat(path, &buffer) == 0;
}
long file_size(const char* path) {
if (path == NULL) {
return -1;
}
struct stat buffer;
if (stat(path, &buffer) != 0) {
return -1;
}
return (long)buffer.st_size;
}
const char* file_extension(const char* path) {
if (path == NULL) {
return NULL;
}
const char* dot = strrchr(path, '.');
if (dot == NULL || dot == path) {
return NULL;
}
return dot;
}

View File

@@ -0,0 +1,161 @@
#include "gui.h"
#include "video_compressor.h"
#include "string_utils.h"
#include <windows.h>
#include <commctrl.h>
#define ID_COMPRESS_BUTTON 101
#define ID_QUALITY_SLIDER 102
#define ID_INPUT_FILE_EDIT 103
#define ID_OUTPUT_FILE_EDIT 104
#define ID_BROWSE_INPUT_BUTTON 105
#define ID_BROWSE_OUTPUT_BUTTON 106
// 全局变量
static HWND g_hwndQualitySlider;
static HWND g_hwndInputFileEdit;
static HWND g_hwndOutputFileEdit;
static HFONT g_hFont = NULL;
// 设置中文字体
static void SetChineseFont(HWND hwnd) {
if (g_hFont == NULL) {
g_hFont = CreateFontW(
16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
GB2312_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
L"Microsoft YaHei"
);
}
if (g_hFont) {
SendMessageW(hwnd, WM_SETFONT, (WPARAM)g_hFont, TRUE);
}
}
BOOL init_gui(HINSTANCE hInstance) {
// 注册窗口类
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = L"VideoCompressorClass";
if (!RegisterClassExW(&wc)) {
return FALSE;
}
// 创建主窗口
HWND hwnd = CreateWindowExW(0, wc.lpszClassName, L"视频压缩工具",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
500, 300, NULL, NULL, hInstance, NULL);
if (!hwnd) {
return FALSE;
}
// 创建控件
create_compression_controls(hwnd);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
return TRUE;
}
void create_compression_controls(HWND hwnd) {
// 设置字体
SetChineseFont(hwnd);
// 创建输入文件选择控件
CreateWindowW(L"STATIC", L"输入文件:", WS_CHILD | WS_VISIBLE,
20, 20, 80, 20, hwnd, NULL, NULL, NULL);
g_hwndInputFileEdit = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER,
110, 20, 250, 20, hwnd, (HMENU)ID_INPUT_FILE_EDIT, NULL, NULL);
CreateWindowW(L"BUTTON", L"浏览...", WS_CHILD | WS_VISIBLE,
370, 20, 60, 20, hwnd, (HMENU)ID_BROWSE_INPUT_BUTTON, NULL, NULL);
// 创建输出文件选择控件
CreateWindowW(L"STATIC", L"输出文件:", WS_CHILD | WS_VISIBLE,
20, 50, 80, 20, hwnd, NULL, NULL, NULL);
g_hwndOutputFileEdit = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER,
110, 50, 250, 20, hwnd, (HMENU)ID_OUTPUT_FILE_EDIT, NULL, NULL);
CreateWindowW(L"BUTTON", L"浏览...", WS_CHILD | WS_VISIBLE,
370, 50, 60, 20, hwnd, (HMENU)ID_BROWSE_OUTPUT_BUTTON, NULL, NULL);
// 创建质量滑块
CreateWindowW(L"STATIC", L"压缩质量(1-10000):", WS_CHILD | WS_VISIBLE,
20, 80, 150, 20, hwnd, NULL, NULL, NULL);
g_hwndQualitySlider = CreateWindowW(TRACKBAR_CLASSW, L"", WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS,
20, 100, 400, 30, hwnd, (HMENU)ID_QUALITY_SLIDER, NULL, NULL);
SendMessageW(g_hwndQualitySlider, TBM_SETRANGE, TRUE, MAKELONG(1, 10000));
SendMessageW(g_hwndQualitySlider, TBM_SETPOS, TRUE, 5000);
// 创建压缩按钮
CreateWindowW(L"BUTTON", L"开始压缩", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
180, 150, 100, 30, hwnd, (HMENU)ID_COMPRESS_BUTTON, NULL, NULL);
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_COMMAND:
if (LOWORD(wParam) == ID_COMPRESS_BUTTON) {
// 处理压缩按钮点击事件
int quality = (int)SendMessageW(g_hwndQualitySlider, TBM_GETPOS, 0, 0);
wchar_t inputFile[MAX_PATH];
GetWindowTextW(g_hwndInputFileEdit, inputFile, MAX_PATH);
wchar_t outputFile[MAX_PATH];
GetWindowTextW(g_hwndOutputFileEdit, outputFile, MAX_PATH);
// 转换为UTF-8
char inputFileUtf8[MAX_PATH * 4];
char outputFileUtf8[MAX_PATH * 4];
WideCharToMultiByte(CP_UTF8, 0, inputFile, -1, inputFileUtf8, sizeof(inputFileUtf8), NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, outputFile, -1, outputFileUtf8, sizeof(outputFileUtf8), NULL, NULL);
// 调用压缩函数
compress_video(inputFileUtf8, outputFileUtf8, quality);
return 0;
} else if (LOWORD(wParam) == ID_BROWSE_INPUT_BUTTON || LOWORD(wParam) == ID_BROWSE_OUTPUT_BUTTON) {
// 文件选择对话框
OPENFILENAMEW ofn;
wchar_t szFile[MAX_PATH] = L"";
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile)/sizeof(szFile[0]);
ofn.lpstrFilter = L"视频文件\0*.mp4;*.avi;*.mkv;*.mov\0所有文件\0*.*\0";
ofn.nFilterIndex = 1;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileNameW(&ofn)) {
HWND targetEdit = (LOWORD(wParam) == ID_BROWSE_INPUT_BUTTON) ?
g_hwndInputFileEdit : g_hwndOutputFileEdit;
SetWindowTextW(targetEdit, szFile);
}
return 0;
}
break;
case WM_DESTROY:
if (g_hFont) {
DeleteObject(g_hFont);
g_hFont = NULL;
}
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}

View File

@@ -0,0 +1,61 @@
#include "logger.h"
#include <time.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
static FILE* log_file = NULL;
static LogLevel current_level = LOG_INFO;
void logger_init(const char* log_file_path) {
if (log_file_path != NULL) {
log_file = fopen(log_file_path, "a");
} else {
log_file = stdout;
}
}
void logger_set_level(LogLevel level) {
current_level = level;
}
void logger_log(LogLevel level, const char* format, ...) {
if (log_file == NULL || level < current_level) {
return;
}
// 获取当前时间
time_t now;
time(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now));
// 日志级别字符串
const char* level_str;
switch (level) {
case LOG_DEBUG: level_str = "DEBUG"; break;
case LOG_INFO: level_str = "INFO"; break;
case LOG_WARNING: level_str = "WARNING"; break;
case LOG_ERROR: level_str = "ERROR"; break;
default: level_str = "UNKNOWN"; break;
}
// 写入时间戳和日志级别
fprintf(log_file, "[%s] [%s] ", time_str, level_str);
// 写入日志内容
va_list args;
va_start(args, format);
vfprintf(log_file, format, args);
va_end(args);
fprintf(log_file, "\n");
fflush(log_file);
}
void logger_close() {
if (log_file != NULL && log_file != stdout) {
fclose(log_file);
}
log_file = NULL;
}

View File

@@ -0,0 +1,26 @@
#include <windows.h>
#include "video_compressor.h"
#include "gui.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// 抑制未使用参数警告
(void)hPrevInstance;
(void)lpCmdLine;
(void)nCmdShow;
// 初始化GUI
if (!init_gui(hInstance)) {
return 1;
}
// 主消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}

View File

@@ -0,0 +1,120 @@
#include "string_utils.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
char* str_copy(char* dest, const char* src, size_t dest_size) {
if (dest == NULL || src == NULL || dest_size == 0) {
return NULL;
}
size_t i;
for (i = 0; i < dest_size - 1 && src[i] != '\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0';
return dest;
}
char* str_concat(char* dest, const char* src, size_t dest_size) {
if (dest == NULL || src == NULL || dest_size == 0) {
return NULL;
}
size_t dest_len = strlen(dest);
if (dest_len >= dest_size) {
return dest;
}
size_t i;
for (i = 0; i < dest_size - dest_len - 1 && src[i] != '\0'; i++) {
dest[dest_len + i] = src[i];
}
dest[dest_len + i] = '\0';
return dest;
}
char* str_trim(char* str) {
if (str == NULL) {
return NULL;
}
char* end;
// 去除前导空白字符
while (isspace((unsigned char)*str)) {
str++;
}
// 如果全是空白字符
if (*str == '\0') {
return str;
}
// 去除尾部空白字符
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) {
end--;
}
// 写入终止符
*(end + 1) = '\0';
return str;
}
int str_starts_with(const char* str, const char* prefix) {
if (str == NULL || prefix == NULL) {
return 0;
}
size_t len_str = strlen(str);
size_t len_prefix = strlen(prefix);
if (len_prefix > len_str) {
return 0;
}
return strncmp(str, prefix, len_prefix) == 0;
}
int str_ends_with(const char* str, const char* suffix) {
if (str == NULL || suffix == NULL) {
return 0;
}
size_t len_str = strlen(str);
size_t len_suffix = strlen(suffix);
if (len_suffix > len_str) {
return 0;
}
return strncmp(str + len_str - len_suffix, suffix, len_suffix) == 0;
}
char* str_to_lower(char* str) {
if (str == NULL) {
return NULL;
}
for (char* p = str; *p != '\0'; p++) {
*p = tolower((unsigned char)*p);
}
return str;
}
char* str_to_upper(char* str) {
if (str == NULL) {
return NULL;
}
for (char* p = str; *p != '\0'; p++) {
*p = toupper((unsigned char)*p);
}
return str;
}

View File

@@ -0,0 +1,323 @@
#include "video_compressor.h"
#include "string_utils.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <stdio.h>
#include <sys/stat.h> // For mkdir()
#include <errno.h> // For errno
// 将质量参数(1-10000)转换为FFmpeg的CRF值(0-51)
static int convert_quality_to_crf(int quality) {
// 更激进的映射关系,确保中等质量也能强力压缩
if (quality < 3000) return 45 - (quality * 15) / 3000; // 低质量区间(30-45)
if (quality < 7000) return 30 - ((quality-3000) * 10) / 4000; // 中等质量区间(20-30)
return 20 - ((quality-7000) * 2) / 3000; // 高质量区间(18-20)
}
int compress_video(const char* input_file, const char* output_file, int quality) {
AVFormatContext *input_ctx = NULL;
AVFormatContext *output_ctx = NULL;
AVCodecContext *encoder_ctx = NULL;
const AVCodec *encoder = NULL;
AVPacket *packet = NULL;
int ret = 0;
int video_stream_index = -1;
int crf = convert_quality_to_crf(quality);
// 打开输入文件
if (avformat_open_input(&input_ctx, input_file, NULL, NULL) < 0) {
fprintf(stderr, "无法打开输入文件\n");
ret = -1;
goto cleanup;
}
// 获取流信息
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
fprintf(stderr, "无法获取流信息\n");
ret = -1;
goto cleanup;
}
// 查找视频流
for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {
if (input_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
fprintf(stderr, "未找到视频流\n");
ret = -1;
goto cleanup;
}
// 创建输出上下文
if (avformat_alloc_output_context2(&output_ctx, NULL, NULL, output_file) < 0) {
fprintf(stderr, "无法创建输出上下文\n");
ret = -1;
goto cleanup;
}
// 打开输出文件
if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&output_ctx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "无法打开输出文件\n");
ret = -1;
goto cleanup;
}
}
// 配置编码器
encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!encoder) {
fprintf(stderr, "未找到H.264编码器\n");
ret = -1;
goto cleanup;
}
encoder_ctx = avcodec_alloc_context3(encoder);
if (!encoder_ctx) {
fprintf(stderr, "无法分配编码器上下文\n");
ret = -1;
goto cleanup;
}
// 设置更激进的编码参数
int64_t input_bit_rate = input_ctx->bit_rate;
if (input_bit_rate <= 0) {
input_bit_rate = 400000; // 默认值
}
// 设置严格的编码参数确保播放兼容性
encoder_ctx->bit_rate = input_bit_rate * 0.5;
encoder_ctx->rc_max_rate = input_bit_rate * 0.7;
encoder_ctx->rc_min_rate = input_bit_rate * 0.3;
encoder_ctx->rc_buffer_size = input_bit_rate * 0.7 / 25;
encoder_ctx->level = 31; // 明确设置level 3.1确保广泛兼容
encoder_ctx->width = input_ctx->streams[video_stream_index]->codecpar->width;
encoder_ctx->height = input_ctx->streams[video_stream_index]->codecpar->height;
encoder_ctx->time_base = (AVRational){1, 25};
encoder_ctx->framerate = (AVRational){25, 1};
encoder_ctx->gop_size = 10;
encoder_ctx->max_b_frames = 1;
encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
// 设置更激进的x264参数
av_opt_set_int(encoder_ctx->priv_data, "crf", crf, 0);
av_opt_set(encoder_ctx->priv_data, "preset", "slow", 0); // 使用slow预设提高压缩率
// 设置强制兼容性参数
av_opt_set(encoder_ctx->priv_data, "profile", "main", 0);
av_opt_set(encoder_ctx->priv_data, "movflags", "+faststart", 0); // 添加流式播放支持
av_opt_set(encoder_ctx->priv_data, "tune", "zerolatency", 0);
av_opt_set(encoder_ctx->priv_data, "x264-params", "ref=1:bframes=0:subme=2:me=dia:analyse=none:trellis=0", 0);
encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
encoder_ctx->thread_count = 4; // 启用4线程编码
encoder_ctx->thread_type = FF_THREAD_FRAME; // 帧级多线程
encoder_ctx->gop_size = 250; // 更大的GOP提高压缩率
encoder_ctx->max_b_frames = 0; // 禁用B帧提高解码兼容性
// 打开编码器
if (avcodec_open2(encoder_ctx, encoder, NULL) < 0) {
fprintf(stderr, "无法打开编码器\n");
ret = -1;
goto cleanup;
}
// 添加视频流到输出文件
AVStream *out_stream = avformat_new_stream(output_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "无法创建输出流\n");
ret = -1;
goto cleanup;
}
// 复制编码器参数到输出流
if (avcodec_parameters_from_context(out_stream->codecpar, encoder_ctx) < 0) {
fprintf(stderr, "无法复制编码器参数\n");
ret = -1;
goto cleanup;
}
// 写入文件头
if (avformat_write_header(output_ctx, NULL) < 0) {
fprintf(stderr, "写入文件头失败\n");
ret = -1;
goto cleanup;
}
packet = av_packet_alloc();
if (!packet) {
fprintf(stderr, "无法分配AVPacket\n");
ret = -1;
goto cleanup;
}
// 初始化解码器
const AVCodec *decoder = avcodec_find_decoder(input_ctx->streams[video_stream_index]->codecpar->codec_id);
if (!decoder) {
fprintf(stderr, "未找到解码器\n");
ret = -1;
goto cleanup;
}
AVCodecContext *decoder_ctx = avcodec_alloc_context3(decoder);
if (!decoder_ctx) {
fprintf(stderr, "无法分配解码器上下文\n");
ret = -1;
goto cleanup;
}
if (avcodec_parameters_to_context(decoder_ctx, input_ctx->streams[video_stream_index]->codecpar) < 0) {
fprintf(stderr, "无法复制解码器参数\n");
ret = -1;
goto cleanup;
}
if (avcodec_open2(decoder_ctx, decoder, NULL) < 0) {
fprintf(stderr, "无法打开解码器\n");
ret = -1;
goto cleanup;
}
// 初始化帧和转换上下文
AVFrame *frame = av_frame_alloc();
AVFrame *tmp_frame = av_frame_alloc();
if (!frame || !tmp_frame) {
fprintf(stderr, "无法分配帧\n");
ret = -1;
goto cleanup;
}
// 分配输入帧缓冲区
frame->format = decoder_ctx->pix_fmt;
frame->width = decoder_ctx->width;
frame->height = decoder_ctx->height;
if (av_frame_get_buffer(frame, 32) < 0) {
fprintf(stderr, "无法分配输入帧缓冲区\n");
ret = -1;
goto cleanup;
}
// 分配输出帧缓冲区
tmp_frame->format = encoder_ctx->pix_fmt;
tmp_frame->width = encoder_ctx->width;
tmp_frame->height = encoder_ctx->height;
if (av_frame_get_buffer(tmp_frame, 32) < 0) {
fprintf(stderr, "无法分配输出帧缓冲区\n");
ret = -1;
goto cleanup;
}
struct SwsContext *sws_ctx = NULL;
sws_ctx = sws_getContext(
decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt,
encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt,
SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr, "无法创建图像转换上下文\n");
ret = -1;
goto cleanup;
}
// 彻底解决目录权限问题
if (mkdir("build") != 0 && errno != EEXIST) {
fprintf(stderr, "错误无法创建build目录(errno=%d),请手动创建并设置写权限\n", errno);
ret = -1;
goto cleanup;
}
// 验证目录可写权限
FILE *test_file = fopen("build/test_permission.tmp", "w");
if (!test_file) {
fprintf(stderr, "致命错误无法写入build目录(errno=%d),请确保:\n1. 目录存在且有写权限\n2. 没有其他程序锁定该目录\n3. 磁盘空间充足\n", errno);
ret = -1;
goto cleanup;
}
fclose(test_file);
remove("build/test_permission.tmp");
// 解码和编码循环
while (av_read_frame(input_ctx, packet) >= 0) {
if (packet->stream_index == video_stream_index) {
// 发送包到解码器
if (avcodec_send_packet(decoder_ctx, packet) < 0) {
fprintf(stderr, "解码错误\n");
continue;
}
// 接收解码后的帧
while (avcodec_receive_frame(decoder_ctx, frame) >= 0) {
// 转换像素格式
sws_scale(sws_ctx, (const uint8_t * const*)frame->data,
frame->linesize, 0, decoder_ctx->height,
tmp_frame->data, tmp_frame->linesize);
// 设置帧参数
tmp_frame->format = encoder_ctx->pix_fmt;
tmp_frame->width = encoder_ctx->width;
tmp_frame->height = encoder_ctx->height;
tmp_frame->pts = frame->pts;
// 发送帧到编码器
if (avcodec_send_frame(encoder_ctx, tmp_frame) < 0) {
fprintf(stderr, "编码错误\n");
break;
}
// 接收编码后的包
while (avcodec_receive_packet(encoder_ctx, packet) >= 0) {
// 写入输出文件
if (av_interleaved_write_frame(output_ctx, packet) < 0) {
fprintf(stderr, "写入帧失败\n");
av_packet_unref(packet);
ret = -1;
goto cleanup;
}
av_packet_unref(packet);
}
}
}
av_packet_unref(packet);
}
// 刷新编码器
avcodec_send_frame(encoder_ctx, NULL);
while (avcodec_receive_packet(encoder_ctx, packet) >= 0) {
if (av_interleaved_write_frame(output_ctx, packet) < 0) {
fprintf(stderr, "写入帧失败\n");
av_packet_unref(packet);
ret = -1;
goto cleanup;
}
av_packet_unref(packet);
}
// 写入文件尾
av_write_trailer(output_ctx);
cleanup:
if (packet) av_packet_free(&packet);
if (frame) av_frame_free(&frame);
if (tmp_frame) av_frame_free(&tmp_frame);
if (sws_ctx) sws_freeContext(sws_ctx);
if (decoder_ctx) avcodec_free_context(&decoder_ctx);
if (input_ctx) avformat_close_input(&input_ctx);
if (output_ctx && !(output_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&output_ctx->pb);
}
if (output_ctx) avformat_free_context(output_ctx);
if (encoder_ctx) avcodec_free_context(&encoder_ctx);
return ret;
}
int init_video_compressor() {
// 新版本FFmpeg不需要显式初始化
return 0;
}
void cleanup_video_compressor() {
// 当前无需特殊清理
}

2
renexe.bat Normal file
View File

@@ -0,0 +1,2 @@
ren bin\Release\net8.0-windows\win-x86\publish\AppStore.exe kortapp.exe
ren bin\Release\net8.0-windows\win-x64\publish\AppStore.exe kortapp.exe

Binary file not shown.

113
zh-TW_README.md Normal file
View File

@@ -0,0 +1,113 @@
# Kortapp-z - Windows應用商店 --主張軟體開源、免費,拒絕廣告
小立一個flag從不接受廣告不停更新
## 專案開源行為
1. 專案程式碼開源,允許任何人使用、修改、分發、商用,但必須註明原作者。
2. 專案文件開源,允許任何人使用、修改、分發、商用,但必須註明原作者。
3. 專案圖示、截圖等資源開源,允許任何人使用、修改、分發、商用,但必須註明原作者。
4. 專案的任何衍生品包括但不限於網站、APP、外掛等必須遵循以上開源協議。
5. 專案不接受任何形式的廣告,不得在任何地方投放廣告。
6. 專案不接受任何形式的捐贈。
7. 專案不接受任何形式的贊助。
8. 專案可以進行PR歡迎任何形式的PR不提交issue也可以
9. 本專案可以PR一些你自己的專案如果star數量不到1k都會被刪除
## 專案簡介
一個簡單的Windows應用商店應用提供軟體下載和管理功能。
提供軟體管理、下載管理、內建工具使用等功能
## 功能特點
- 簡潔的軟體下載介面
- 下載進度管理
- 支援後台下載
- 美觀的應用卡片展示
- 功能化、結構化的程式碼處理
## 構建與打包
### 系統要求
- .NET 8.0 SDK
- Windows 10/11
### 打包指令
#### 32位版本
```bash
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
```
#### 64位版本
```bash
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
```
打包後的可執行文件將包含指定的應用程式圖示,輸出路徑為:
```
bin\Release\net8.0-windows\[platform]\publish
```
### 進階選項
- 添加`--self-contained true`可生成獨立包(體積較大)
- 添加`-p:PublishTrimmed=true`可減小包體積(實驗性)
## 專案結構
```
kortapp-z/
├── MainForm.cs # 主視窗邏輯
├── DownloadManager.cs # 下載管理
├── AppCard.cs # 應用卡片控制項
├── DownloadItem.cs # 下載項控制項
├── img/ # 圖片資源
│ ├── ico/ # 圖示文件
│ └└── png/ # 應用截圖
└└── resource/ # 資源文件
└└── aria2c.exe # 下載工具
```
## 執行要求
- .NET 8.0執行時(如果使用框架依賴發布)
- Windows 10或更高版本
## 授權許可
MIT License
Copyright (c) 2025 zsyg
## 其他網站
gitee鏡像倉庫:https://gitee.com/chr_super/kortapp-z (目前已停止維護)
## 維護
由於gitee我沒怎麼用而且操作麻煩gitee鏡像將不會繼續同步有懂得人可以幫我搞下鏡像嗎qq 3872006562也可以b站直接私信我會在readme中鳴謝的謝謝各位
由於和Daye發生了矛盾所以windowscleaner將永遠不上架我要自己努力
提示由於github上傳文件的限制img/png/NET.png請改名為.NET.png否則程式可能出現無法預料的問題
每一個人都可以通過PR添加屬於自己的合法軟體
作者郵箱:
```
3872006562@qq.com
```
作者qq號:
```
3872006562
```
qq群
```
1043867176
```
b站帳號
```
Zayisynth
```