Skip to content

Commit

Permalink
👍Support for saving videos via browser extension
Browse files Browse the repository at this point in the history
- Addition of browser extension (twitter-video-dl-send)
- Add video storage server (twitter-video-dl-server.py)

Closes: #11
  • Loading branch information
7rikazhexde committed Feb 4, 2024
1 parent f96d8f7 commit 6bdd7b0
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 11 deletions.
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ This project is based on the original code of the [inteoryx / twitter-video-dl](
- [twitter-video-dl-for-sc](#twitter-video-dl-for-sc)
- [ToC](#toc)
- [Demo (Shortcuts)](#demo-shortcuts)
- [Demo (Shortcuts for Mac browser)](#demo-shortcuts-for-mac-browser)
- [Demo (Shortcuts for Mac Browser)](#demo-shortcuts-for-mac-browser)
- [Demo (Browser Extension)](#demo-browser-extension)
- [Usage](#usage)
- [Installing FFmpeg](#installing-ffmpeg)
- [For Shortcuts](#for-shortcuts)
- [For Mac Browser](#for-mac-browser)
- [For Browser Extension](#for-browser-extension)
- [CLI For Windows / Mac / Linux](#cli-for-windows--mac--linux)
- [Auto Retry Feature](#auto-retry-feature)
- [Other](#other)
Expand All @@ -23,12 +25,16 @@ This project is based on the original code of the [inteoryx / twitter-video-dl](
|One video per post|Mixing images and videos in one post|Mixing images and videos in a thread|
|:---:|:---:|:---:|
|<img src="./demo/demo1_v1_30fps_400x866.gif" width="80%" alt="One video per post">|<img src="./demo/demo2_v1_30fps_400x866.gif" width="80%" alt="Mixing images and videos in one post">|<img src="./demo/demo3_v2_30fps_400x866.gif" width="80%" alt="Mixing images and videos in a thread">|
|[Original Post Link(Media)](https://twitter.com/i/status/1650829030609022981)|[Original Post Link(Media)](https://twitter.com/tw_7rikazhexde/status/1650808610157662211?s=20)|[Original post Link(Media)](https://twitter.com/tw_7rikazhexde/status/1650812768138981376?s=20)|
|[Original Post Link(Media)](https://x.com/tw_7rikazhexde/status/1650804112987136000?s=20)|[Original Post Link(Media)](https://twitter.com/tw_7rikazhexde/status/1650808610157662211?s=20)|[Original Post Link(Media)](https://twitter.com/tw_7rikazhexde/status/1650812768138981376?s=20)|

## Demo (Shortcuts for Mac browser)
## Demo (Shortcuts for Mac Browser)

<img src="./demo/demo1_twitter-video-dl-sc-for-mac_60fps_1440x900.gif" alt="twitter-video-dl-sc-for-mac demo">

## Demo (Browser Extension)

<img src="./demo/demo1_twitter-video-dl-sc-for-server_60fps_1280x720.gif" alt="twitter-video-dl-sc-for-server demo">

## Usage

### Installing FFmpeg
Expand Down Expand Up @@ -82,6 +88,21 @@ Only differences from the procedure for iPhone and iPad are described.

2. When executing the shortcut, start **the video-posted post in the browser** that you start on your Mac, and then execute ***twitter-video-dl-sc-for-mac-browser*** from the tab Sharing. If it saves successfully, the destination will be displayed. ([See demo video](#demo-shortcuts-for-mac-browser))

## For Browser Extension

> [!WARNING]
> **Browsers that have been tested are chrome and brave.**
> [!NOTE]
> **Please check [See demo video](#demo-browser-extension)**
1. extensions > load unpackaged extensions > Local Package
**[twitter-video-dl-send](./browser_extension/twitter-video-dl-send/)**
2. Start the server (`poetry run python twitter-video-dl-server.py`)
3. Open the X(Twitter) web page where the video was posted.
4. Specify the filename and URL (not required) in the extension and run the process of saving the video
5. If there are no errors, the video will be saved in the **output** folder

## CLI For Windows / Mac / Linux

> [!NOTE]
Expand Down
8 changes: 8 additions & 0 deletions browser_extension/twitter-video-dl-send/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function sendUrl(url, fileName) {
fetch(`http://localhost:3000/?url=${encodeURIComponent(url)}&fileName=${encodeURIComponent(fileName)}`);
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "sendUrl") {
sendUrl(request.url, request.fileName);
}
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions browser_extension/twitter-video-dl-send/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"manifest_version": 2,
"name": "twitter-video-dl-send",
"version": "0.0.1",
"author": "7rikaz_h785 <7rikaz.h785.stat2ltas41lcijad@gmail.com>",
"homepage_url": "https://github.com/7rikazhexde/twitter-video-dl-for-sc",
"permissions": ["activeTab", "http://localhost:3000/"],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_popup": "popup.html",
"default_width": 400,
"default_height": 200
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
43 changes: 43 additions & 0 deletions browser_extension/twitter-video-dl-send/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, sans-serif;
width: 450px;
}
#fileNameInput, #urlInput, #languageSelect {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
}
#sendCurrentUrl, #sendInputUrl {
background-color: #2a4fc9;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 12px;
cursor: pointer;
width: 100%;
}
#sendCurrentUrl:hover, #sendInputUrl:hover {
background-color: #2a4fc9;
}
</style>
</head>
<body>
<h1 id="title"></h1>
<select id="languageSelect">
<option value="en">English</option>
<option value="ja">日本語</option>
</select>
<input type="text" id="fileNameInput" placeholder="">
<button id="sendCurrentUrl"></button>
<input type="text" id="urlInput" placeholder="">
<button id="sendInputUrl"></button>
<script src="popup.js"></script>
</body>
</html>
72 changes: 72 additions & 0 deletions browser_extension/twitter-video-dl-send/popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const languageSelect = document.getElementById('languageSelect');
const sendCurrentUrlButton = document.getElementById('sendCurrentUrl');
const sendInputUrlButton = document.getElementById('sendInputUrl');
const fileNameInput = document.getElementById('fileNameInput');
const urlInput = document.getElementById('urlInput');
const title = document.getElementById('title');

const text = {
en: {
title: 'twitter-video-dl-send',
fileNamePlaceholder: 'Enter file name',
sendCurrentUrl: 'Send current URL',
sendInputUrl: 'Send the URL you entered',
urlPlaceholder: 'Enter URL',
sent: 'Sent',
},
ja: {
title: 'twitter-video-dl-send',
fileNamePlaceholder: 'ファイル名を入力',
sendCurrentUrl: '現在のURLを送信',
sendInputUrl: '入力したURLを送信',
urlPlaceholder: 'URLを入力',
sent: '送信済み',
},
};

function updateLanguage() {
const lang = languageSelect.value;
localStorage.setItem('language', lang);
title.innerText = text[lang].title;
fileNameInput.placeholder = text[lang].fileNamePlaceholder;
sendCurrentUrlButton.innerText = text[lang].sendCurrentUrl;
sendInputUrlButton.innerText = text[lang].sendInputUrl;
urlInput.placeholder = text[lang].urlPlaceholder;
}

languageSelect.addEventListener('change', updateLanguage);

window.addEventListener('DOMContentLoaded', () => {
const savedLanguage = localStorage.getItem('language') || 'en';
languageSelect.value = savedLanguage;
updateLanguage();
});

document.getElementById('sendCurrentUrl').addEventListener('click', function() {
const fileName = document.getElementById('fileNameInput').value;
chrome.tabs.query({active: true, currentWindow: true}, tabs => {
chrome.runtime.sendMessage({action: "sendUrl", url: tabs[0].url, fileName: fileName});
});
this.style.backgroundColor = '#888888';
this.innerText = text[languageSelect.value].sent;
setTimeout(() => {
this.style.backgroundColor = '#2a4fc9';
this.innerText = text[languageSelect.value].sendCurrentUrl;
}, 2000);
});

document.getElementById('sendInputUrl').addEventListener('click', function() {
const url = document.getElementById('urlInput').value;
const fileName = document.getElementById('fileNameInput').value;
if (url) {
chrome.runtime.sendMessage({action: "sendUrl", url: url, fileName: fileName});
this.style.backgroundColor = '#888888';
this.innerText = text[languageSelect.value].sent;
setTimeout(() => {
this.style.backgroundColor = '#2a4fc9';
this.innerText = text[languageSelect.value].sendInputUrl;
}, 2000);
} else {
alert('URLを入力してください');
}
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = "This project is based on the original code of the [inteoryx / twi
license = "Unlicense"
name = "twitter-video-dl-for-sc"
readme = "README.md"
version = "0.2.6"
version = "0.2.7"

[tool.poetry.dependencies]
python = "^3.11.0"
Expand Down
20 changes: 13 additions & 7 deletions src/twitter_video_dl/twitter_video_dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,6 @@ def create_video_urls(json_data):
except KeyError:
pass

print(media_list)

if media_list:
if "video_info" in media_list[0]:
video_url_list, gif_ptn = get_non_card_type_extended_entities_vid_urls(
Expand Down Expand Up @@ -638,11 +636,19 @@ def download_videos(video_urls, output_file, output_folder_path, gif_ptn):
print("Invalid input. Please enter 'y' or 'n'.")

with requests.get(video_url, stream=True) as response:
with open(output_file_name, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print(f"Video {output_file_name} downloaded successfully.")
if response.status_code == 200:
with open(output_file_name, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print(f"Video {output_file_name} downloaded successfully.")
else:
print(
f"Failed to download video from {video_url}. Status code: {response.status_code}"
)
print(
f"If you are using the correct Twitter URL this suggests a bug in the script. Please open a GitHub issue and copy and paste this message. Tweet url: {video_url}"
)

if gif_ptn:
# Covert mp4 to gif
Expand Down
41 changes: 41 additions & 0 deletions twitter-video-dl-server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs, urlparse

import src.twitter_video_dl.twitter_video_dl as tvdl

DCEBUG_MODE = False


class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
query = urlparse(self.path).query
params = parse_qs(query)
url = params.get("url", [""])[0]
fileName = params.get("fileName", [""])[0]
if url:
tvdl.download_video_for_sc(url, fileName)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(b"URL received")
else:
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(b"No URL received")

def log_message(self, format, *args):
if DCEBUG_MODE:
# Display log only when debug mode is True.
super().log_message(format, *args)


def run(server_class=HTTPServer, handler_class=RequestHandler, port=3000):
server_address = ("", port)
httpd = server_class(server_address, handler_class)
print(f"Starting server on port {port}")
httpd.serve_forever()


if __name__ == "__main__":
run()

0 comments on commit 6bdd7b0

Please sign in to comment.