Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Force LF line endings
* text=auto eol=lf

# Set file types
*.php text
*.sh text eol=lf
*.md text
*.yml text
*.json text
*.xml text
*.env text

# Exclude tests and dev files from export
phpcs.xml export-ignore
php-cs-fixer.dist.php export-ignore
.dockerignore export-ignore
composer.lock export-ignore

README.md export-ignore
CHANGELOG.md export-ignore
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
tools: composer:v2

- name: Validate composer.json
run: composer validate --strict
continue-on-error: true

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
continue-on-error: true

- name: PHP Syntax check
run: find src -name "*.php" -exec php -l {} \;
continue-on-error: true
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.env
.env.local
.env.*.local
/vendor/
/node_modules/
/.idea/
/.vscode/
.DS_Store
*.log
*.cache

docker-compose.override.yml
*.pid

composer.lock

.phpunit.result.cache
/tests/output/

/build/
/dist/

*.bak
*.swp
*.swo

sessions
docs_md
session.mad
*.madeline
*.madeline.*
madeline.phar
madeline.phar.version
madeline.php

*.save
*.save.1

*.save.*
18 changes: 18 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude('vendor')
->exclude('data');

return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'array_syntax' => ['syntax' => 'short'],
'no_unused_imports' => true,
'single_quote' => true,
'no_empty_phpdoc' => true,
'not_operator_with_successor_space' => false,
])
->setFinder($finder);
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,20 @@ Added functionality to send initial status messages when gathering peers and sta
### Added & Fixed:

* Handle additional RPCErrorException cases

---

## [3.1.0] - 2026-04-13

# Refactor BroadcastManager for improved functionality
- Updated BroadcastManager class to improve functionality and code structure.
- Added support for handling broadcast IDs, enhanced error handling, and refactored methods to accept optional chat IDs.

### Added:
- added `isActive()` to check active
- added option to set chatId as null

### Fixed:
- fixed `progress()` to update progress state from all methods

---
160 changes: 111 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Manage broadcasts efficiently: send messages, media albums, pin/unpin messages,
[![Packagist
Version](https://img.shields.io/packagist/v/wizardloop/broadcastmanager)](https://packagist.org/packages/wizardloop/broadcastmanager)
[![Packagist Downloads](https://img.shields.io/packagist/dt/wizardloop/broadcastmanager?color=blue)](https://packagist.org/packages/wizardloop/broadcastmanager)
![CI](https://github.com/WizardLoop/BroadcastManager/actions/workflows/ci.yml/badge.svg)

---

Expand Down Expand Up @@ -58,29 +59,6 @@ Version](https://img.shields.io/packagist/v/wizardloop/broadcastmanager)](https:

---

## 📁 Repository Structure

```
BroadcastManager/
├── src/
│ └── BroadcastManager.php
├── data/
│ └── .gitkeep
├── composer.json
├── README.md
├── LICENSE
└── CHANGELOG.md
```

---

## 💻 Requirements

* [MadelineProto](https://docs.madelineproto.xyz/)
* [amphp/amp](https://amphp.org/)

---

## ⚡ Installation

```bash
Expand All @@ -97,6 +75,10 @@ require 'vendor/autoload.php';

## 🚀 Usage Example

---
## Send Broadcast

### 1) live progress update in message to admin:
```php
use BroadcastTool\BroadcastManager;

Expand All @@ -105,10 +87,90 @@ $manager = new BroadcastManager($api);
$manager->broadcastWithProgress($users, $messages, $adminChatId, true, 20);
```

### 2) track on progress without message:
This method returns an integer ID that can be used.

```php
use BroadcastTool\BroadcastManager;

$manager = new BroadcastManager($api);

$broadcastId = $manager->broadcastWithProgress($users, $messages, null, true, 20);

/**
* Get progress (can be polled)
*/
$progress = $manager->progress($broadcastId);

if ($progress !== null) {

// 📊 Core stats
$processed = $progress['processed'];
$success = $progress['success'];
$failed = $progress['failed'];
$pending = $progress['pending'];
$flood = $progress['flood'];

// 📈 Progress %
$progressPercent = $progress['progressPercent'];

// 📦 Breakdown
$sent = $progress['breakdown']['sent'];
$deleted = $progress['breakdown']['deleted'];
$unpin = $progress['breakdown']['unpin'];

// ⚙️ State
$done = $progress['done'];
$paused = $progress['paused'];
$cancel = $progress['cancel'];

// ⏱ Timing
$startedAt = $progress['startedAt'];

/**
* Example usage
*/
echo "Progress: {$progressPercent}%\n";
echo "Sent: {$sent}\n";
echo "Failed: {$failed}\n";

if ($done) {
echo "Broadcast finished!";
}

if ($paused) {
echo "Broadcast paused...";
}
}
```

```php
* progress return array|null {
* processed: int, // total processed items (sent + deleted + unpin + failed)
* success: int, // successful operations (sent + deleted + unpin)
* failed: int, // failed operations count
* pending: int, // remaining items in queue
* flood: int, // FLOOD_WAIT occurrences
*
* progressPercent: float, // completion percentage (processed / total)
*
* breakdown: array {
* sent: int,
* deleted: int,
* unpin: int
* },
*
* done: bool, // process finished
* paused: bool, // process paused
* cancel: bool, // process cancelled
*
* startedAt: float // microtime start timestamp
* }
```

---

## Filer Peers

```php
$filterSub = $manager->filterPeers($users, 'users');
$targets = $filterSub['targets']; # array
Expand All @@ -121,64 +183,64 @@ $total = $filterSub['total']; # int
## ⏸ Control Broadcasts

```php
$manager->pause();
$manager->resume();
$manager->cancel();
$manager->pause($broadcastId);
$manager->resume($broadcastId);
$manager->cancel($broadcastId);
```

Check state:
### Check state:
```php
if ($manager->isPaused()) echo "Paused";
if ($manager->isCancelled()) echo "Cancelled";
if (!$manager->hasLastBroadcast()) echo "No last Broadcast do delete";
if (!$manager->hasAllBroadcast()) echo "No all Broadcast to delete";
print_r($manager->progress());
if ($manager->isActive($broadcastId));
if ($manager->isPaused($broadcastId));
if ($manager->isCancelled($broadcastId));
if (!$manager->hasLastBroadcast($broadcastId));
if (!$manager->hasAllBroadcast($broadcastId));
print_r($manager->progress($broadcastId));
```

Set data dir:
### Set data dir:
```php
BroadcastManager::setDataDir(__DIR__ . '/data');
BroadcastManager::setDataDir(__DIR__ . '/data'); // default: __DIR__ . '/../data'
```
_default is: __DIR__ . '/../data'_

---

## 🧹 Delete Last Broadcast

```php
$manager->deleteLastBroadcastForAll($users, $adminChatId, 20);
$broadcastId = $manager->deleteLastBroadcastForAll($users, $adminChatId, 20);
```

---

## ♻️ Delete All Broadcast

```php
$manager->deleteAllBroadcastsForAll($users, $adminChatId, 20);
$broadcastId = $manager->deleteAllBroadcastsForAll($users, $adminChatId, 20);
```

---

## 📊 Get Last Broadcast Data

```php
$manager->lastBroadcastData();
$broadcastId = $manager->lastBroadcastData();
```

---

## 📌 Pin / Unpin Messages

Pin last broadcast automatically:
## Pin last broadcast automatically:

```php
$manager->broadcastWithProgress(..., pin: true);
$broadcastId = $manager->broadcastWithProgress(..., pin: true);
```

Unpin all messages:
## Unpin all messages:

```php
$manager->unpinAllMessagesForAll(...);
$broadcastId = $manager->unpinAllMessagesForAll(...);
```

---
Expand All @@ -199,11 +261,11 @@ $message = [

## ⚙️ Advanced Options

* **Concurrency** Number of parallel workers.
* **Filter Types** 'users', 'groups', 'channels', 'all'
* **Album Handling** JSON-based albums with multiple media files.
* **Retries & Delays** Automatic retries with backoff.
* **Progress Tracking** Real-time broadcast stats with `progress()`.
* **Concurrency** - Number of parallel workers.
* **Filter Types** - 'users', 'groups', 'channels', 'all'
* **Album Handling** - JSON-based albums with multiple media files.
* **Retries & Delays** - Automatic retries with backoff.
* **Progress Tracking** - Real-time broadcast stats with `progress()`.

---

Expand All @@ -219,7 +281,7 @@ $message = [

## 📄 License

**GNU AGPL-3.0** see [LICENSE](LICENSE).
**GNU AGPL-3.0** - see [LICENSE](LICENSE).

---

Expand Down
7 changes: 7 additions & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<ruleset name="BroadcastManager">
<description>PHP CodeSniffer configuration</description>
<file>src</file>
<exclude-pattern>vendor/*</exclude-pattern>
<rule ref="PSR12"/>
</ruleset>
Loading
Loading