snapsaver-downloader 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -0
- package/dist/Download.d.ts +17 -0
- package/dist/Download.js +311 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +15 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +42 -0
- package/package.json +45 -0
package/README.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# SnapSaver Downloader
|
2
|
+
|
3
|
+
[](https://www.npmjs.com/package/snapsaver-downloader)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
5
|
+
|
6
|
+
An unofficial Node.js package to download media from Facebook, Instagram, and TikTok using SnapSave API.
|
7
|
+
|
8
|
+
## Features
|
9
|
+
|
10
|
+
- 📥 Download videos and images from:
|
11
|
+
- Facebook posts, reels, and watch videos
|
12
|
+
- Instagram posts and reels
|
13
|
+
- TikTok videos
|
14
|
+
- 📱 Support for multiple quality options (when available)
|
15
|
+
- 🌐 URL normalization and validation
|
16
|
+
- 🔄 Automatic platform detection
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
```bash
|
21
|
+
npm install snapsaver-downloader
|
22
|
+
```
|
23
|
+
|
24
|
+
Or with yarn:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
yarn add snapsaver-downloader
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
```typescript
|
33
|
+
import { SnapSaver } from 'snapsaver-downloader';
|
34
|
+
|
35
|
+
// Example: Download from Facebook
|
36
|
+
async function downloadMedia() {
|
37
|
+
try {
|
38
|
+
const result = await SnapSaver('https://www.facebook.com/watch/?v=1377532133417378');
|
39
|
+
|
40
|
+
if (result.success) {
|
41
|
+
console.log('Media found:', result.data);
|
42
|
+
// Access download URLs:
|
43
|
+
const mediaUrls = result.data?.media?.map(item => item.url);
|
44
|
+
console.log('Download URLs:', mediaUrls);
|
45
|
+
} else {
|
46
|
+
console.error('Error:', result.message);
|
47
|
+
}
|
48
|
+
} catch (error) {
|
49
|
+
console.error('Failed to download:', error);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
downloadMedia();
|
54
|
+
```
|
55
|
+
|
56
|
+
### Supported URLs
|
57
|
+
|
58
|
+
The package supports various URL formats:
|
59
|
+
|
60
|
+
#### Facebook
|
61
|
+
- `https://www.facebook.com/watch/?v=1234567890`
|
62
|
+
- `https://www.facebook.com/share/v/123ABC456/`
|
63
|
+
- `https://www.facebook.com/username/videos/1234567890`
|
64
|
+
- `https://fb.watch/abcdef123/`
|
65
|
+
|
66
|
+
#### Instagram
|
67
|
+
- `https://www.instagram.com/p/ABC123def/`
|
68
|
+
- `https://www.instagram.com/reel/ABC123def/`
|
69
|
+
- URLs with query parameters (e.g., `?utm_source=ig_web_copy_link`)
|
70
|
+
|
71
|
+
#### TikTok
|
72
|
+
- `https://www.tiktok.com/@username/video/1234567890`
|
73
|
+
- `https://vt.tiktok.com/ABCDEF/`
|
74
|
+
|
75
|
+
## API Reference
|
76
|
+
|
77
|
+
### SnapSaver(url: string): Promise<SnapSaveDownloaderResponse>
|
78
|
+
|
79
|
+
The main function to download media from supported social platforms.
|
80
|
+
|
81
|
+
#### Parameters
|
82
|
+
|
83
|
+
- `url` (string): URL of the social media post to download
|
84
|
+
|
85
|
+
#### Returns
|
86
|
+
|
87
|
+
Returns a Promise that resolves to a `SnapSaveDownloaderResponse` object:
|
88
|
+
|
89
|
+
```typescript
|
90
|
+
interface SnapSaveDownloaderResponse {
|
91
|
+
success: boolean;
|
92
|
+
message?: string;
|
93
|
+
data?: SnapSaveDownloaderData;
|
94
|
+
}
|
95
|
+
|
96
|
+
interface SnapSaveDownloaderData {
|
97
|
+
description?: string;
|
98
|
+
preview?: string;
|
99
|
+
media?: SnapSaveDownloaderMedia[];
|
100
|
+
}
|
101
|
+
|
102
|
+
interface SnapSaveDownloaderMedia {
|
103
|
+
resolution?: string;
|
104
|
+
shouldRender?: boolean;
|
105
|
+
thumbnail?: string;
|
106
|
+
type?: "image" | "video";
|
107
|
+
url?: string;
|
108
|
+
}
|
109
|
+
```
|
110
|
+
|
111
|
+
#### Response Structure
|
112
|
+
|
113
|
+
- `success` - Boolean indicating if the download was successful
|
114
|
+
- `message` - Error message (only present when `success` is false)
|
115
|
+
- `data` - Result data (only present when `success` is true)
|
116
|
+
- `description` - Description of the post (when available)
|
117
|
+
- `preview` - Preview image URL (when available)
|
118
|
+
- `media` - Array of media objects containing:
|
119
|
+
- `type` - Media type ("video" or "image")
|
120
|
+
- `url` - Direct download URL
|
121
|
+
- `resolution` - Resolution (for videos, when available)
|
122
|
+
- `thumbnail` - Thumbnail URL (for videos, when available)
|
123
|
+
- `shouldRender` - Whether the media needs special rendering
|
124
|
+
|
125
|
+
## Utilities
|
126
|
+
|
127
|
+
The package exports several utility functions that might be useful:
|
128
|
+
|
129
|
+
```typescript
|
130
|
+
import {
|
131
|
+
normalizeURL,
|
132
|
+
detectPlatformFromURL,
|
133
|
+
fixThumbnail
|
134
|
+
} from 'snapsaver-downloader/dist/utils';
|
135
|
+
|
136
|
+
// Normalize a URL (add www if missing)
|
137
|
+
const normalizedUrl = normalizeURL('https://facebook.com/video/123');
|
138
|
+
// Result: 'https://www.facebook.com/video/123'
|
139
|
+
|
140
|
+
// Detect platform from URL
|
141
|
+
const platform = detectPlatformFromURL('https://www.instagram.com/reel/ABC123/');
|
142
|
+
// Result: 'Instagram'
|
143
|
+
```
|
144
|
+
|
145
|
+
## Limitations
|
146
|
+
|
147
|
+
- This package relies on the SnapSave.app service, which may change its API without notice
|
148
|
+
- Some platforms may block scraping attempts or change their URL structure
|
149
|
+
- For high-volume applications, consider implementing rate limiting
|
150
|
+
|
151
|
+
## Contributing
|
152
|
+
|
153
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
154
|
+
|
155
|
+
1. Fork the project
|
156
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
157
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
158
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
159
|
+
5. Open a Pull Request
|
160
|
+
|
161
|
+
## License
|
162
|
+
|
163
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
164
|
+
|
165
|
+
## Disclaimer
|
166
|
+
|
167
|
+
This package is not affiliated with, endorsed by, or connected to SnapSave.app or any of the social media platforms it supports. It is provided for educational purposes only. Always respect the terms of service of the platforms you are downloading content from, and ensure you have the right to download and use the content.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import type { SnapSaveDownloaderResponse } from "./types";
|
2
|
+
/**
|
3
|
+
* SnapSaver service - orchestrates the workflow but delegates specific tasks
|
4
|
+
*/
|
5
|
+
export declare class SnapSaverService {
|
6
|
+
private readonly urlValidator;
|
7
|
+
private readonly decoder;
|
8
|
+
private readonly extractor;
|
9
|
+
private readonly apiClient;
|
10
|
+
constructor();
|
11
|
+
/**
|
12
|
+
* Main method to download media from social platforms via SnapSave
|
13
|
+
* @param url URL of the social media post to download
|
14
|
+
* @returns Response containing success status and download data
|
15
|
+
*/
|
16
|
+
download(url: string): Promise<SnapSaveDownloaderResponse>;
|
17
|
+
}
|
package/dist/Download.js
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SnapSaverService = void 0;
|
4
|
+
const cheerio_1 = require("cheerio");
|
5
|
+
const utils_1 = require("./utils");
|
6
|
+
/**
|
7
|
+
* URL Validator class - responsible for validating URLs against supported platforms
|
8
|
+
*/
|
9
|
+
class UrlValidator {
|
10
|
+
constructor(regexes = [utils_1.facebookRegex, utils_1.instagramRegex, utils_1.tiktokRegex]) {
|
11
|
+
this.supportedRegexes = regexes;
|
12
|
+
}
|
13
|
+
/**
|
14
|
+
* Validates if the URL is from a supported platform
|
15
|
+
* @param url URL to validate
|
16
|
+
* @returns Boolean indicating if the URL is supported
|
17
|
+
*/
|
18
|
+
isValid(url) {
|
19
|
+
return this.supportedRegexes.some(regex => url.match(regex));
|
20
|
+
}
|
21
|
+
}
|
22
|
+
/**
|
23
|
+
* SnapSave Decoder class - responsible for all decoding and decryption logic
|
24
|
+
*/
|
25
|
+
class SnapSaveDecoder {
|
26
|
+
/**
|
27
|
+
* Decodes SnapApp encoded content
|
28
|
+
* @param args Array of arguments from the encoded content
|
29
|
+
* @returns Decoded content
|
30
|
+
*/
|
31
|
+
decodeSnapApp(args) {
|
32
|
+
let [encodedContent, u, charMap, subtractValue, base, decodedResult] = args;
|
33
|
+
/**
|
34
|
+
* Internal decoder function for number conversion
|
35
|
+
*/
|
36
|
+
const decodeNumber = (value, fromBase, toBase) => {
|
37
|
+
const charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".split("");
|
38
|
+
const fromCharset = charset.slice(0, fromBase);
|
39
|
+
const toCharset = charset.slice(0, toBase);
|
40
|
+
// @ts-expect-error - Known limitation in type inference for this algorithm
|
41
|
+
let decimal = value.split("").reverse().reduce((sum, char, index) => {
|
42
|
+
if (fromCharset.indexOf(char) !== -1)
|
43
|
+
return sum += fromCharset.indexOf(char) * (Math.pow(fromBase, index));
|
44
|
+
return sum;
|
45
|
+
}, 0);
|
46
|
+
let result = "";
|
47
|
+
while (decimal > 0) {
|
48
|
+
result = toCharset[decimal % toBase] + result;
|
49
|
+
decimal = (decimal - (decimal % toBase)) / toBase;
|
50
|
+
}
|
51
|
+
return result || "0";
|
52
|
+
};
|
53
|
+
decodedResult = "";
|
54
|
+
for (let i = 0, len = encodedContent.length; i < len; i++) {
|
55
|
+
let segment = "";
|
56
|
+
while (encodedContent[i] !== charMap[Number(base)]) {
|
57
|
+
segment += encodedContent[i];
|
58
|
+
i++;
|
59
|
+
}
|
60
|
+
for (let j = 0; j < charMap.length; j++) {
|
61
|
+
segment = segment.replace(new RegExp(charMap[j], "g"), j.toString());
|
62
|
+
}
|
63
|
+
// @ts-expect-error - Known limitation in type inference for this algorithm
|
64
|
+
decodedResult += String.fromCharCode(decodeNumber(segment, base, 10) - subtractValue);
|
65
|
+
}
|
66
|
+
return this.fixEncoding(decodedResult);
|
67
|
+
}
|
68
|
+
/**
|
69
|
+
* Fixes UTF-8 encoding issues in the decoded content
|
70
|
+
*/
|
71
|
+
fixEncoding(str) {
|
72
|
+
const bytes = new Uint8Array(str.split("").map(char => char.charCodeAt(0)));
|
73
|
+
return new TextDecoder("utf-8").decode(bytes);
|
74
|
+
}
|
75
|
+
/**
|
76
|
+
* Extracts the encoded arguments from SnapSave HTML response
|
77
|
+
*/
|
78
|
+
getEncodedSnapApp(data) {
|
79
|
+
return data.split("decodeURIComponent(escape(r))}(")[1]
|
80
|
+
.split("))")[0]
|
81
|
+
.split(",")
|
82
|
+
.map(v => v.replace(/"/g, "").trim());
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* Extracts the decoded HTML content from SnapSave response
|
86
|
+
*/
|
87
|
+
getDecodedSnapSave(data) {
|
88
|
+
return data.split("getElementById(\"download-section\").innerHTML = \"")[1]
|
89
|
+
.split("\"; document.getElementById(\"inputData\").remove(); ")[0]
|
90
|
+
.replace(/\\(\\)?/g, "");
|
91
|
+
}
|
92
|
+
/**
|
93
|
+
* Decrypts the SnapSave response by chaining the decoding functions
|
94
|
+
* @param data Raw HTML response from SnapSave
|
95
|
+
* @returns Decrypted HTML content
|
96
|
+
*/
|
97
|
+
decrypt(data) {
|
98
|
+
return this.getDecodedSnapSave(this.decodeSnapApp(this.getEncodedSnapApp(data)));
|
99
|
+
}
|
100
|
+
}
|
101
|
+
/**
|
102
|
+
* Media Extractor class - responsible for extracting media from different HTML layouts
|
103
|
+
*/
|
104
|
+
class MediaExtractor {
|
105
|
+
/**
|
106
|
+
* Extract metadata from HTML content
|
107
|
+
* @param $ Cheerio API instance
|
108
|
+
* @returns Extracted metadata
|
109
|
+
*/
|
110
|
+
extractMetadata($) {
|
111
|
+
const data = {};
|
112
|
+
const description = $("span.video-des").text().trim();
|
113
|
+
const preview = $("article.media > figure").find("img").attr("src");
|
114
|
+
if (description)
|
115
|
+
data.description = description;
|
116
|
+
if (preview)
|
117
|
+
data.preview = preview;
|
118
|
+
return data;
|
119
|
+
}
|
120
|
+
/**
|
121
|
+
* Extract media items from table layout
|
122
|
+
* @param $ Cheerio API instance
|
123
|
+
* @returns Array of extracted media
|
124
|
+
*/
|
125
|
+
extractTableMedia($) {
|
126
|
+
const media = [];
|
127
|
+
$("tbody > tr").each((_, el) => {
|
128
|
+
var _a;
|
129
|
+
const $el = $(el);
|
130
|
+
const $td = $el.find("td");
|
131
|
+
const resolution = $td.eq(0).text();
|
132
|
+
let mediaUrl = $td.eq(2).find("a").attr("href") || $td.eq(2).find("button").attr("onclick");
|
133
|
+
const shouldRender = /get_progressApi/ig.test(mediaUrl || "");
|
134
|
+
if (shouldRender) {
|
135
|
+
mediaUrl = "https://snapsave.app" + ((_a = /get_progressApi\('(.*?)'\)/.exec(mediaUrl || "")) === null || _a === void 0 ? void 0 : _a[1]) || mediaUrl;
|
136
|
+
}
|
137
|
+
media.push({
|
138
|
+
resolution,
|
139
|
+
...(shouldRender ? { shouldRender } : {}),
|
140
|
+
url: mediaUrl,
|
141
|
+
type: resolution ? "video" : "image"
|
142
|
+
});
|
143
|
+
});
|
144
|
+
return media;
|
145
|
+
}
|
146
|
+
/**
|
147
|
+
* Extract media items from card layout
|
148
|
+
* @param $ Cheerio API instance
|
149
|
+
* @returns Array of extracted media
|
150
|
+
*/
|
151
|
+
extractCardMedia($) {
|
152
|
+
const media = [];
|
153
|
+
$("div.card").each((_, el) => {
|
154
|
+
const cardBody = $(el).find("div.card-body");
|
155
|
+
const aText = cardBody.find("a").text().trim();
|
156
|
+
const url = cardBody.find("a").attr("href");
|
157
|
+
const type = aText === "Download Photo" ? "image" : "video";
|
158
|
+
media.push({
|
159
|
+
url,
|
160
|
+
type
|
161
|
+
});
|
162
|
+
});
|
163
|
+
return media;
|
164
|
+
}
|
165
|
+
/**
|
166
|
+
* Extract media from simple layout
|
167
|
+
* @param $ Cheerio API instance
|
168
|
+
* @returns Array of extracted media
|
169
|
+
*/
|
170
|
+
extractSimpleMedia($) {
|
171
|
+
const media = [];
|
172
|
+
const url = $("a").attr("href") || $("button").attr("onclick");
|
173
|
+
const aText = $("a").text().trim();
|
174
|
+
const type = aText === "Download Photo" ? "image" : "video";
|
175
|
+
media.push({
|
176
|
+
url,
|
177
|
+
type
|
178
|
+
});
|
179
|
+
return media;
|
180
|
+
}
|
181
|
+
/**
|
182
|
+
* Extract media from download items layout
|
183
|
+
* @param $ Cheerio API instance
|
184
|
+
* @returns Array of extracted media
|
185
|
+
*/
|
186
|
+
extractDownloadItemsMedia($) {
|
187
|
+
const media = [];
|
188
|
+
$("div.download-items").each((_, el) => {
|
189
|
+
const itemThumbnail = $(el).find("div.download-items__thumb > img").attr("src");
|
190
|
+
const itemBtn = $(el).find("div.download-items__btn");
|
191
|
+
const url = itemBtn.find("a").attr("href");
|
192
|
+
const spanText = itemBtn.find("span").text().trim();
|
193
|
+
const type = spanText === "Download Photo" ? "image" : "video";
|
194
|
+
media.push({
|
195
|
+
url,
|
196
|
+
...(type === "video" && itemThumbnail ? {
|
197
|
+
thumbnail: (0, utils_1.fixThumbnail)(itemThumbnail)
|
198
|
+
} : {}),
|
199
|
+
type
|
200
|
+
});
|
201
|
+
});
|
202
|
+
return media;
|
203
|
+
}
|
204
|
+
}
|
205
|
+
/**
|
206
|
+
* SnapSave API Client - responsible for making API requests
|
207
|
+
*/
|
208
|
+
class SnapSaveApiClient {
|
209
|
+
constructor(apiUrl = "https://snapsave.app/action.php?lang=en") {
|
210
|
+
this.apiUrl = apiUrl;
|
211
|
+
}
|
212
|
+
/**
|
213
|
+
* Make a request to the SnapSave API
|
214
|
+
* @param url URL to download from
|
215
|
+
* @returns Raw HTML response
|
216
|
+
*/
|
217
|
+
async fetchMedia(url) {
|
218
|
+
// Prepare request to SnapSave API
|
219
|
+
const formData = new URLSearchParams();
|
220
|
+
formData.append("url", (0, utils_1.normalizeURL)(url));
|
221
|
+
const response = await fetch(this.apiUrl, {
|
222
|
+
method: "POST",
|
223
|
+
headers: {
|
224
|
+
"accept": "*/*",
|
225
|
+
"content-type": "application/x-www-form-urlencoded",
|
226
|
+
"origin": "https://snapsave.app",
|
227
|
+
"referer": "https://snapsave.app/",
|
228
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0"
|
229
|
+
},
|
230
|
+
body: formData
|
231
|
+
});
|
232
|
+
// Return raw response
|
233
|
+
return response.text();
|
234
|
+
}
|
235
|
+
}
|
236
|
+
/**
|
237
|
+
* SnapSaver service - orchestrates the workflow but delegates specific tasks
|
238
|
+
*/
|
239
|
+
class SnapSaverService {
|
240
|
+
constructor() {
|
241
|
+
this.urlValidator = new UrlValidator();
|
242
|
+
this.decoder = new SnapSaveDecoder();
|
243
|
+
this.extractor = new MediaExtractor();
|
244
|
+
this.apiClient = new SnapSaveApiClient();
|
245
|
+
}
|
246
|
+
/**
|
247
|
+
* Main method to download media from social platforms via SnapSave
|
248
|
+
* @param url URL of the social media post to download
|
249
|
+
* @returns Response containing success status and download data
|
250
|
+
*/
|
251
|
+
async download(url) {
|
252
|
+
try {
|
253
|
+
// Validate URL against supported platforms
|
254
|
+
if (!this.urlValidator.isValid(url)) {
|
255
|
+
return {
|
256
|
+
success: false,
|
257
|
+
message: "Invalid URL"
|
258
|
+
};
|
259
|
+
}
|
260
|
+
// Fetch media from SnapSave API
|
261
|
+
const html = await this.apiClient.fetchMedia(url);
|
262
|
+
// Decrypt the response
|
263
|
+
const decodedHtml = this.decoder.decrypt(html);
|
264
|
+
// Parse HTML and extract media
|
265
|
+
const $ = (0, cheerio_1.load)(decodedHtml);
|
266
|
+
// Initialize data structure
|
267
|
+
const data = {};
|
268
|
+
let media = [];
|
269
|
+
// Extract data based on the HTML structure
|
270
|
+
if ($("table.table").length || $("article.media > figure").length) {
|
271
|
+
// Extract metadata
|
272
|
+
Object.assign(data, this.extractor.extractMetadata($));
|
273
|
+
// Extract media based on layout
|
274
|
+
if ($("table.table").length) {
|
275
|
+
media = this.extractor.extractTableMedia($);
|
276
|
+
}
|
277
|
+
else if ($("div.card").length) {
|
278
|
+
media = this.extractor.extractCardMedia($);
|
279
|
+
}
|
280
|
+
else {
|
281
|
+
media = this.extractor.extractSimpleMedia($);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
// Extract media from download items layout
|
285
|
+
else if ($("div.download-items").length) {
|
286
|
+
media = this.extractor.extractDownloadItemsMedia($);
|
287
|
+
}
|
288
|
+
// Validate results
|
289
|
+
if (!media.length) {
|
290
|
+
return {
|
291
|
+
success: false,
|
292
|
+
message: "No downloadable media found"
|
293
|
+
};
|
294
|
+
}
|
295
|
+
// Add media to data and return
|
296
|
+
data.media = media;
|
297
|
+
return {
|
298
|
+
success: true,
|
299
|
+
data
|
300
|
+
};
|
301
|
+
}
|
302
|
+
catch (error) {
|
303
|
+
console.error("SnapSaver error:", error);
|
304
|
+
return {
|
305
|
+
success: false,
|
306
|
+
message: "Failed to process download request"
|
307
|
+
};
|
308
|
+
}
|
309
|
+
}
|
310
|
+
}
|
311
|
+
exports.SnapSaverService = SnapSaverService;
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
import { SnapSaveDownloaderResponse } from "./types";
|
2
|
+
/**
|
3
|
+
* Main function to download media from social platforms via SnapSave
|
4
|
+
* @param url URL of the social media post to download
|
5
|
+
* @returns Response containing success status and download data
|
6
|
+
*/
|
7
|
+
export declare const SnapSaver: (url: string) => Promise<SnapSaveDownloaderResponse>;
|
package/dist/index.js
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SnapSaver = void 0;
|
4
|
+
const Download_1 = require("./Download");
|
5
|
+
// Create singleton instance
|
6
|
+
const snapSaverInstance = new Download_1.SnapSaverService();
|
7
|
+
/**
|
8
|
+
* Main function to download media from social platforms via SnapSave
|
9
|
+
* @param url URL of the social media post to download
|
10
|
+
* @returns Response containing success status and download data
|
11
|
+
*/
|
12
|
+
const SnapSaver = async (url) => {
|
13
|
+
return snapSaverInstance.download(url);
|
14
|
+
};
|
15
|
+
exports.SnapSaver = SnapSaver;
|
package/dist/types.d.ts
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
export interface SnapSaveDownloaderMedia {
|
2
|
+
resolution?: string;
|
3
|
+
shouldRender?: boolean;
|
4
|
+
thumbnail?: string;
|
5
|
+
type?: "image" | "video";
|
6
|
+
url?: string;
|
7
|
+
}
|
8
|
+
export interface SnapSaveDownloaderData {
|
9
|
+
description?: string;
|
10
|
+
preview?: string;
|
11
|
+
media?: SnapSaveDownloaderMedia[];
|
12
|
+
}
|
13
|
+
export interface SnapSaveDownloaderResponse {
|
14
|
+
success: boolean;
|
15
|
+
message?: string;
|
16
|
+
data?: SnapSaveDownloaderData;
|
17
|
+
}
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* Regular expression patterns for various social media platforms
|
3
|
+
* Each regex is designed to match the URL format for a specific platform
|
4
|
+
*/
|
5
|
+
export declare const facebookRegex: RegExp;
|
6
|
+
export declare const instagramRegex: RegExp;
|
7
|
+
export declare const tiktokRegex: RegExp;
|
8
|
+
export declare const youtubeRegex: RegExp;
|
9
|
+
export declare const twitterRegex: RegExp;
|
10
|
+
export declare const normalizeURL: (url: string) => string;
|
11
|
+
export declare const fixThumbnail: (url: string) => string;
|
12
|
+
export declare const detectPlatformFromURL: (url: string) => string | null;
|
package/dist/utils.js
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* Regular expression patterns for various social media platforms
|
4
|
+
* Each regex is designed to match the URL format for a specific platform
|
5
|
+
*/
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
7
|
+
exports.detectPlatformFromURL = exports.fixThumbnail = exports.normalizeURL = exports.twitterRegex = exports.youtubeRegex = exports.tiktokRegex = exports.instagramRegex = exports.facebookRegex = void 0;
|
8
|
+
// Facebook URLs including watch, reels, videos, posts and fb.watch short links
|
9
|
+
exports.facebookRegex = /^https?:\/\/(?:www\.|web\.|m\.)?facebook\.com\/(watch(\?v=|\/\?v=)[0-9]+(?!\/)|reel\/[0-9]+|[a-zA-Z0-9.\-_]+\/(videos|posts)\/[0-9]+|[0-9]+\/(videos|posts)\/[0-9]+|[a-zA-Z0-9]+\/(videos|posts)\/[0-9]+|share\/(v|r)\/[a-zA-Z0-9]+\/?)([^/?#&]+).*$|^https:\/\/fb\.watch\/[a-zA-Z0-9]+$/;
|
10
|
+
// Instagram URLs for posts, reels, stories, tv and share links
|
11
|
+
exports.instagramRegex = /^https?:\/\/(?:www\.)?instagram\.com\/(?:p|reel|reels|tv|stories|share)\/([^/?#&]+).*/;
|
12
|
+
// TikTok URLs for various formats including user videos, photos and short links
|
13
|
+
exports.tiktokRegex = /^https?:\/\/(?:www\.|m\.|vm\.|vt\.)?tiktok\.com\/(?:@[^/]+\/(?:video|photo)\/\d+|v\/\d+|t\/[\w]+|[\w-]+)\/?/i;
|
14
|
+
// YouTube URLs for standard watch URLs, shorts and embed links
|
15
|
+
exports.youtubeRegex = /^https?:\/\/(?:www\.)?(?:youtube\.com\/(?:watch\?(?:.*&)?v=|shorts\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:[?&][^#\s]*)?/;
|
16
|
+
// Twitter/X URLs for tweet status links
|
17
|
+
exports.twitterRegex = /^https?:\/\/(?:www\.)?(?:twitter\.com|x\.com)\/(?:#!\/)?(?:[\w_]+\/status(?:es)?\/)([0-9]+)(?:[?&][^#\s]*)?/;
|
18
|
+
const normalizeURL = (url) => {
|
19
|
+
return /^(https?:\/\/)(?!www\.)[a-z0-9]+/i.test(url)
|
20
|
+
? url.replace(/^(https?:\/\/)([^./]+\.[^./]+)(\/.*)?$/, "$1www.$2$3")
|
21
|
+
: url;
|
22
|
+
};
|
23
|
+
exports.normalizeURL = normalizeURL;
|
24
|
+
const fixThumbnail = (url) => {
|
25
|
+
const toReplace = "https://snapinsta.app/photo.php?photo=";
|
26
|
+
return url.includes(toReplace) ? decodeURIComponent(url.replace(toReplace, "")) : url;
|
27
|
+
};
|
28
|
+
exports.fixThumbnail = fixThumbnail;
|
29
|
+
const detectPlatformFromURL = (url) => {
|
30
|
+
if (exports.facebookRegex.test(url))
|
31
|
+
return "Facebook";
|
32
|
+
if (exports.instagramRegex.test(url))
|
33
|
+
return "Instagram";
|
34
|
+
if (exports.tiktokRegex.test(url))
|
35
|
+
return "TikTok";
|
36
|
+
if (exports.youtubeRegex.test(url))
|
37
|
+
return "YouTube";
|
38
|
+
if (exports.twitterRegex.test(url))
|
39
|
+
return "Twitter";
|
40
|
+
return null;
|
41
|
+
};
|
42
|
+
exports.detectPlatformFromURL = detectPlatformFromURL;
|
package/package.json
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
{
|
2
|
+
"name": "snapsaver-downloader",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "An Unofficial Package to Download From Facebook, TikTok and Instagram. Relais on SnapSave",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"types": "dist/index.d.ts",
|
7
|
+
"scripts": {
|
8
|
+
"build": "tsc",
|
9
|
+
"prepublishOnly": "npm run build",
|
10
|
+
"test": "jest"
|
11
|
+
},
|
12
|
+
"repository": {
|
13
|
+
"type": "git",
|
14
|
+
"url": "git+https://github.com/gitnasr/snapsaver-dl.git"
|
15
|
+
},
|
16
|
+
"keywords": [
|
17
|
+
"snapsaver",
|
18
|
+
"instagram",
|
19
|
+
"facebook",
|
20
|
+
"twitter"
|
21
|
+
],
|
22
|
+
"author": "gitnasr",
|
23
|
+
"license": "MIT",
|
24
|
+
"bugs": {
|
25
|
+
"url": "https://github.com/gitnasr/snapsaver-dl/issues"
|
26
|
+
},
|
27
|
+
"homepage": "https://github.com/gitnasr/snapsaver-dl#readme",
|
28
|
+
"dependencies": {
|
29
|
+
"cheerio": "^1.0.0"
|
30
|
+
},
|
31
|
+
"devDependencies": {
|
32
|
+
"@types/jest": "^29.5.14",
|
33
|
+
"@types/node": "^18.0.0",
|
34
|
+
"jest": "^29.7.0",
|
35
|
+
"jest-fetch-mock": "^3.0.3",
|
36
|
+
"ts-jest": "^29.3.2",
|
37
|
+
"ts-node": "^10.9.1",
|
38
|
+
"typescript": "^5.0.0"
|
39
|
+
},
|
40
|
+
"files": [
|
41
|
+
"dist/**/*",
|
42
|
+
"LICENSE",
|
43
|
+
"README.md"
|
44
|
+
]
|
45
|
+
}
|