Skip to content

Commit

Permalink
start
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadForoutan committed Sep 24, 2024
0 parents commit 68c1575
Show file tree
Hide file tree
Showing 39 changed files with 4,714 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ffmpeg/ffmpeg.exe filter=lfs diff=lfs merge=lfs -text
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
env
dist
build
gfw/DNS_IP_traffic_info.txt
229 changes: 229 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import time
import webbrowser
import threading
import os
import sys
import yt_dlp
from urllib.parse import urlparse
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit, QCheckBox, QPushButton,
QVBoxLayout, QMessageBox, QProgressBar, QComboBox, QFileDialog, QHBoxLayout
)

# GFW Proxy import (assumed it's correct)
from gfw.pyprox_HTTPS_current import start as gfw_proxy_start

# Set the ffmpeg path based on OS
def get_ffmpeg_path():
if sys.platform == "win32":
return os.path.join(os.path.dirname(__file__), 'ffmpeg', 'ffmpeg.exe')
elif sys.platform == "darwin": # macOS
return os.path.join(os.path.dirname(__file__), 'ffmpeg', 'ffmpeg')
else: # Linux or Unix
return os.path.join(os.path.dirname(__file__), 'ffmpeg', 'ffmpeg')


class DownloadThread(QThread):
progress_signal = pyqtSignal(int)
finished_signal = pyqtSignal(str)

def __init__(self, video_url, proxy, is_playlist, quality, audio_only, download_path):
super().__init__()
self.video_url = video_url
self.proxy = proxy
self.is_playlist = is_playlist
self.quality = quality
self.audio_only = audio_only
self.download_path = download_path

def run(self):
# Get the FFmpeg location
ffmpeg_path = get_ffmpeg_path()

# Basic YDL options
ydl_opts = {
'progress_hooks': [self.progress_hook],
'outtmpl': os.path.join(self.download_path, '%(title)s.%(ext)s'),
'ffmpeg_location': ffmpeg_path, # Specify FFmpeg binary
'retries': 5,
'noprogress': True,
'ignoreerrors': True,
'continuedl': False,
}

if self.proxy:
ydl_opts['proxy'] = self.proxy

if self.audio_only:
ydl_opts['format'] = 'bestaudio/best'
ydl_opts['postprocessors'] = [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}]
else:
# Set video quality based on user selection
if self.quality == '720p':
ydl_opts['format'] = 'bestvideo[height<=720]+bestaudio/best'
elif self.quality == '480p':
ydl_opts['format'] = 'bestvideo[height<=480]+bestaudio/best'
elif self.quality == '1080p':
ydl_opts['format'] = 'bestvideo[height<=1080]+bestaudio/best'
else:
ydl_opts['format'] = 'best'

try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([self.video_url])
self.finished_signal.emit("دانلود و ترکیب فایل‌ها با موفقیت به پایان رسید!")

except Exception as e:
self.finished_signal.emit(f"دانلود شکست خورد: {str(e)}")

def progress_hook(self, d):
if d['status'] == 'downloading':
downloaded_bytes = d.get('downloaded_bytes', 0)
total_bytes = d.get('total_bytes', d.get('total_bytes_estimate', 0))

if total_bytes > 0:
progress = int(downloaded_bytes / total_bytes * 100)
self.progress_signal.emit(progress)
elif d['status'] == 'error':
self.finished_signal.emit("دانلود شکست خورد. لطفا دوباره تلاش کنید.")


class YouTubeApp(QWidget):
def __init__(self):
super().__init__()
self.init_ui()

def open_link(self, url):
webbrowser.open(url)

def init_ui(self):
# Create the widgets
self.note_label = QLabel("با باز بودن برنامه میتونید روی پورت ۴۵۰۰ یوتوب روی بدون فیلترشکن نگاه کنید")

self.tut_label = QLabel('<a href="https://www.example.com">برای آموزش کلید کنید</a>')
self.tut_label.linkActivated.connect(self.open_link)

self.url_label = QLabel("YouTube Video URL:")
self.url_input = QLineEdit(self)

self.proxy_label = QLabel("Proxy (optional):")
self.proxy_input = QLineEdit(self)
self.proxy_input.setText("http://127.0.0.1:4500")

self.playlist_checkbox = QCheckBox("Is this a playlist?", self)

self.quality_label = QLabel("Select Quality:")
self.quality_combo = QComboBox(self)
self.quality_combo.addItems(['720p', '480p', '1080p'])
self.quality_combo.setCurrentText('720p')

self.audio_only_checkbox = QCheckBox("Download Audio Only (MP3)", self)

self.path_label = QLabel("Download Path:")
self.path_input = QLineEdit(self)
self.path_input.setReadOnly(True)

self.browse_button = QPushButton("Browse", self)
self.browse_button.clicked.connect(self.browse_folder)

self.set_default_download_path()

self.progress_bar = QProgressBar(self)
self.progress_bar.setValue(0)
self.progress_bar.setMaximum(100)

self.progress_bar_note = QLabel("تکمیل شدن دانلود چند مرحله داره.\n"
"۱. دانلود ویدیو\n"
"۲. دانلود صدا\n"
"۳. ترکیب کردن تصویر و صدا\n"
"به همین دلیل ممکنه چند بار به صد درصد برسه.")

self.submit_button = QPushButton("Submit", self)
self.submit_button.clicked.connect(self.start_download)

# Layout configuration
layout = QVBoxLayout()
layout.addWidget(self.note_label)
layout.addWidget(self.tut_label)
layout.addWidget(self.url_label)
layout.addWidget(self.url_input)
layout.addWidget(self.proxy_label)
layout.addWidget(self.proxy_input)
layout.addWidget(self.playlist_checkbox)
layout.addWidget(self.quality_label)
layout.addWidget(self.quality_combo)
layout.addWidget(self.audio_only_checkbox)
layout.addWidget(self.path_label)
layout.addWidget(self.path_input)
layout.addWidget(self.browse_button)
layout.addWidget(self.progress_bar)
layout.addWidget(self.progress_bar_note)
layout.addWidget(self.submit_button)

self.setLayout(layout)
self.setWindowTitle('YouTube Video Downloader')
self.setGeometry(100, 100, 400, 350)

def set_default_download_path(self):
if sys.platform == 'win32':
default_path = os.path.join(os.getenv('USERPROFILE'), 'Downloads')
elif sys.platform == 'darwin':
default_path = os.path.join(os.path.expanduser('~'), 'Downloads')
else:
default_path = os.path.join(os.path.expanduser('~'), 'Downloads')

self.path_input.setText(default_path)

def browse_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Select Download Folder")
if folder:
self.path_input.setText(folder)

def start_download(self):
video_url = self.url_input.text()
proxy = self.proxy_input.text()
is_playlist = self.playlist_checkbox.isChecked()
quality = self.quality_combo.currentText()
audio_only = self.audio_only_checkbox.isChecked()
download_path = self.path_input.text()

if not video_url:
QMessageBox.warning(self, "Input Error", "لطفا لینک ویدیو یوتیوب را وارد کنید")
return

if not download_path:
QMessageBox.warning(self, "Input Error", "لطفا مسیر ذخیره‌سازی را انتخاب کنید")
return

self.submit_button.setEnabled(False)

self.download_thread = DownloadThread(video_url, proxy, is_playlist, quality, audio_only, download_path)
self.download_thread.progress_signal.connect(self.update_progress_bar)
self.download_thread.finished_signal.connect(self.download_finished)
self.download_thread.start()

def update_progress_bar(self, value):
self.progress_bar.setValue(value)

def download_finished(self, message):
QMessageBox.information(self, "Download Status", message)
self.submit_button.setEnabled(True)
self.progress_bar.setValue(0)


if __name__ == '__main__':
# Start the GFW proxy in a separate thread
gfw_thread = threading.Thread(target=gfw_proxy_start)
gfw_thread.daemon = True
gfw_thread.start()
time.sleep(1)

app = QApplication(sys.argv)
window = YouTubeApp()
window.show()
sys.exit(app.exec_())
43 changes: 43 additions & 0 deletions app.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
['app.py'], # Main script
pathex=[], # Additional paths, if needed
binaries=[], # External binaries (we'll add ffmpeg later)
datas=[('ffmpeg/ffmpeg.exe', 'ffmpeg')], # Add ffmpeg to the bundle
hiddenimports=[], # Any hidden imports can be added here
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[], # Modules to exclude
noarchive=False,
)

# Build a .pyz archive of all the pure Python files
pyz = PYZ(a.pure)

# Bundle the .pyz with binaries, scripts, and any additional files
exe = EXE(
pyz,
a.scripts, # Scripts to be included
a.binaries, # External binaries like ffmpeg
a.datas, # Data files like ffmpeg.exe
[],
name='app', # Name of the final executable
debug=False,
bootloader_ignore_signals=False,
strip=True,
noarchive=True,
upx=True, # Use UPX to compress the executable (optional)
upx_exclude=[],
runtime_tmpdir=None,
console=False, # Set to False if you don't want a console window
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
onefile=True, # Bundle everything into one .exe file
)
5 changes: 5 additions & 0 deletions gfw/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
env
dist
build
DNS_IP_traffic_info.txt
__pycache__
22 changes: 22 additions & 0 deletions gfw/Android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# نحوه اجرا
1. ابتدا کد پایتون را روی گوشی (یا کامپیوتر) اجرا کنید <br>
(ویدئو آموزشی از نحوه اجرای کد پایتون در گوشی های اندرویدی https://t.me/ircfspace/124)
2. کانفیگ HTTP را روی nekobox یا matsuri بسازید مطابق شکل زیر

<img src="/asset/neko_http_menu.jpg?raw=true" width="500" ><br><br>
اگر پایتون روی گوشی اجرا شده آدرس 127.0.0.1 و اگر روی کامپیوتر باشد ادرس ip کامپیوتر مثلا 192.168.1.2 را میدهید<br>
<img src="/asset/neko_http_config.jpg?raw=true" width="500" ><br><br>
اگر روی vpn mode هستید باید ترافیک پایتون را از vpn مستثنی کنید <br>
<img src="/asset/neko_bypass_app.jpg?raw=true" width="500" ><br><br>
3. در صورت تمایل میتوانید بجای ساخت کانفیگ ، فایل آماده json را import کنید (و بعد باید پایتون را از vpn مستثنی کنید)

# رفع اشکال
- برنامه v2rayNG روی گوشی از پروتکل HTTP پشتیبانی نمیکند بنابراین از nekobox یا matsuri استفاده کنید
- اگر مشکل loading video دارید از نت ایرانسل استفاده کنید
- از داخل کد ، num_fragment را میتوانید از 10 تا 100 یا حتی بیشتر به دلخواه تنظیم کنید
- زمان fragment_sleep را از 0.001 تا 0.01 به دلخواه تنظیم کنید

# آپدیت 30-2-1402
- قسمت logging از کد حذف شد چون نیاز به دسترسی برای نوشتن فایل داشت و در برخی گوشی ها خطا میداد.
- تمام print ها کامنت شد که پردازش روی گوشی ایجاد نکند
- کانفیگ مخصوص nekobox و matsuri قرار داده شد
Loading

0 comments on commit 68c1575

Please sign in to comment.