-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
98e45fd
commit 07874d0
Showing
6 changed files
with
289 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
SRC_URL=https://... | ||
OUT_FILE=/downloads/video.mp4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
name: Build and Push Docker Image | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
tags: | ||
- '*' | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build-and-push: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout Repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
with: | ||
driver-opts: image=moby/buildkit:latest | ||
|
||
- name: Log in to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ github.repository_owner }} | ||
password: ${{ secrets.DOCKER_PASSWORD }} | ||
|
||
- name: Log in to the Container registry | ||
uses: docker/login-action@v3 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Clone repo to build | ||
run: git clone https://github.com/${{ github.repository }}.git repo | ||
|
||
- name: Build and push image | ||
uses: docker/build-push-action@v5 | ||
with: | ||
context: . | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
tags: | | ||
${{ github.repository }}:${{ github.ref_name }} | ||
ghcr.io/${{ github.repository }}:${{ github.ref_name }} | ||
cache-from: type=gha | ||
cache-to: type=gha,mode=max | ||
|
||
- name: Push latest image | ||
uses: docker/build-push-action@v5 | ||
with: | ||
context: . | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
tags: | | ||
${{ github.repository }}:latest | ||
ghcr.io/${{ github.repository }}:latest | ||
cache-from: type=gha | ||
cache-to: type=gha,mode=max | ||
if: startsWith(github.ref, 'refs/tags/') | ||
|
||
- name: Docker Hub Description | ||
uses: peter-evans/dockerhub-description@v4 | ||
with: | ||
username: ${{ github.repository_owner }} | ||
password: ${{ secrets.DOCKER_PASSWORD }} | ||
repository: ${{ github.repository }} | ||
short-description: ${{ github.event.repository.description }} | ||
enable-url-completion: true | ||
|
||
create-release: | ||
runs-on: ubuntu-latest | ||
needs: build-and-push | ||
permissions: write-all | ||
if: startsWith(github.ref, 'refs/tags/') | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v3 | ||
|
||
- name: Update CHANGELOG | ||
id: changelog | ||
uses: requarks/changelog-action@v1 | ||
with: | ||
token: ${{ github.token }} | ||
tag: ${{ github.ref_name }} | ||
|
||
- name: Create Release | ||
id: create_release | ||
uses: actions/create-release@v1 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
with: | ||
tag_name: ${{ github.ref_name }} | ||
release_name: v${{ github.ref_name }} | ||
body: | | ||
Container images for this release: | ||
- Docker Hub: `${{ github.repository }}:${{ github.ref_name }}` | ||
- GitHub Container Registry: `ghcr.io/${{ github.repository }}:${{ github.ref_name }}` | ||
${{ steps.changelog.outputs.changes }} | ||
draft: false | ||
prerelease: false | ||
|
||
- name: Commit CHANGELOG.md | ||
uses: stefanzweifel/git-auto-commit-action@v4 | ||
with: | ||
branch: main | ||
commit_message: 'docs: update CHANGELOG.md for ${{ github.ref_name }} [skip ci]' | ||
file_pattern: CHANGELOG.md | ||
|
||
- name: Docker Hub Description | ||
uses: peter-evans/dockerhub-description@v4 | ||
with: | ||
username: ${{ github.repository_owner }} | ||
password: ${{ secrets.DOCKER_PASSWORD }} | ||
repository: ${{ github.repository }} | ||
short-description: ${{ github.event.repository.description }} | ||
enable-url-completion: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
FROM python | ||
RUN apt-get update && apt-get install -y \ | ||
youtube-dl \ | ||
&& ln -s /usr/bin/yt-dlp /usr/local/bin/youtube-dl \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
RUN python -m pip install requests tqdm moviepy ffmpeg-python | ||
COPY video.py /video.py | ||
VOLUME /downloads | ||
WORKDIR /downloads | ||
ENTRYPOINT ["python"] | ||
CMD ["/video.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# vimeo-dl | ||
|
||
A container image based on [Javi3rV script](https://gist.github.com/alexeygrigorev/a1bc540925054b71e1a7268e50ad55cd?permalink_comment_id=5279414#gistcomment-5279414) to download segmented videos from vimeo. | ||
It supports playlist.json and master.json urls. | ||
|
||
|
||
## Example usage | ||
|
||
### From docker CLI | ||
|
||
```bash | ||
docker run \ | ||
-e 'SRC_URL=https://...' \ | ||
-e 'OUT_FILE=/downloads/video.mp4' \ | ||
-v $(pwd)/out:/downloads \ | ||
--rm -it davidecavestro/vimeo-dl | ||
``` | ||
|
||
### From docker compose | ||
|
||
```yaml | ||
version: "3" | ||
|
||
services: | ||
downloader: | ||
build: | ||
context: . | ||
volumes: | ||
- ./out:/downloads | ||
environment: | ||
- SRC_URL=${SRC_URL} | ||
- OUT_FILE=${OUT_FILE} | ||
- MAX_WORKERS=${MAX_WORKERS} | ||
``` | ||
passing the url from `.env` file | ||
```.env | ||
SRC_URL=https://... | ||
OUT_FILE=/downloads/video.mp4 | ||
MAX_WORKERS=5 | ||
``` | ||
|
||
|
||
## Image project home | ||
|
||
https://github.com/davidecavestro/vimeo-dl | ||
|
||
|
||
## Disclaimer | ||
|
||
This software is released just for educational purposes. | ||
**Please do not use it for illegal activities.** | ||
|
||
## Credits | ||
|
||
Entirely based on [alexeygrigorev](https://github.com/alexeygrigorev)'s [vimeo-download.py gist](https://gist.github.com/alexeygrigorev/a1bc540925054b71e1a7268e50ad55cd) and refining comments, just with some minor tweaks. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
services: | ||
downloader: | ||
# build: | ||
# context: . | ||
image: davidecavestro/vimeo-dl | ||
volumes: | ||
- ./out:/downloads | ||
environment: | ||
- SRC_URL=${SRC_URL} | ||
- OUT_FILE=${OUT_FILE} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import os | ||
import sys | ||
import base64 | ||
import requests | ||
import subprocess | ||
from concurrent.futures import ThreadPoolExecutor | ||
|
||
from tqdm import tqdm | ||
from moviepy.editor import * | ||
import ffmpeg | ||
|
||
|
||
url = os.getenv("SRC_URL") or input('enter [master|playlist].json url: ') | ||
name = os.getenv("OUT_FILE") or input('enter output name: ') | ||
max_workers = min(int(os.getenv("MAX_WORKERS", 5)), 15) | ||
|
||
if 'master.json' in url: | ||
url = url[:url.find('?')] + '?query_string_ranges=1' | ||
url = url.replace('master.json', 'master.mpd') | ||
print(url) | ||
subprocess.run(['youtube-dl', url, '-o', name]) | ||
sys.exit(0) | ||
|
||
|
||
def download_segment(segment_url, segment_path): | ||
resp = requests.get(segment_url, stream=True) | ||
if resp.status_code != 200: | ||
print('not 200!') | ||
print(segment_url) | ||
return | ||
with open(segment_path, 'wb') as segment_file: | ||
for chunk in resp: | ||
segment_file.write(chunk) | ||
|
||
def download(what, to, base, max_workers): | ||
print('saving', what['mime_type'], 'to', to) | ||
init_segment = base64.b64decode(what['init_segment']) | ||
|
||
segment_urls = [base + segment['url'] for segment in what['segments']] | ||
segment_paths = [f"segment_{i}.tmp" for i in range(len(segment_urls))] | ||
|
||
with ThreadPoolExecutor(max_workers=max_workers) as executor: | ||
list(tqdm(executor.map(download_segment, segment_urls, segment_paths), total=len(segment_urls))) | ||
|
||
with open(to, 'wb') as file: | ||
file.write(init_segment) | ||
for segment_path in segment_paths: | ||
with open(segment_path, 'rb') as segment_file: | ||
file.write(segment_file.read()) | ||
os.remove(segment_path) | ||
|
||
print('done') | ||
|
||
|
||
base_url = url[:url.rfind('/', 0, -26) + 1] | ||
content = requests.get(url).json() | ||
|
||
vid_heights = [(i, d['height']) for (i, d) in enumerate(content['video'])] | ||
vid_idx, _ = max(vid_heights, key=lambda _h: _h[1]) | ||
|
||
audio_quality = [(i, d['bitrate']) for (i, d) in enumerate(content['audio'])] | ||
audio_idx, _ = max(audio_quality, key=lambda _h: _h[1]) | ||
|
||
video = content['video'][vid_idx] | ||
audio = content['audio'][audio_idx] | ||
base_url = base_url + content['base_url'] | ||
|
||
video_tmp_file = 'video.mp4' | ||
audio_tmp_file = 'audio.mp4' | ||
|
||
download(video, video_tmp_file, base_url + video['base_url'], max_workers) | ||
download(audio, audio_tmp_file, base_url + audio['base_url'], max_workers) | ||
|
||
def combine_video_audio(video_file, audio_file, output_file): | ||
try: | ||
video_stream = ffmpeg.input(video_file) | ||
audio_stream = ffmpeg.input(audio_file) | ||
|
||
ffmpeg.output(video_stream, audio_stream, output_file, vcodec='copy', acodec='copy').run(overwrite_output=True) | ||
|
||
print(f"Fragments joined into {output_file}") | ||
except ffmpeg.Error as e: | ||
print(f"Cannot join fragments: {e.stderr.decode()}") | ||
|
||
combine_video_audio('video.mp4', 'audio.mp4', name) | ||
|
||
os.remove(video_tmp_file) | ||
os.remove(audio_tmp_file) |