Skip to content

Commit

Permalink
v10.1.2 Fix videos downloading
Browse files Browse the repository at this point in the history
  • Loading branch information
saschaheim committed Mar 1, 2022
1 parent 3bec05e commit ae1c3cf
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 115 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# <img style="float: left; vertical-align: bottom; " width="35" src="https://upload.wikimedia.org/wikipedia/commons/4/4c/Typescript_logo_2020.svg"> [instantgram] v10.1.1
![GitHub release](https://img.shields.io/badge/release-v10.1.1-green)
# <img style="float: left; vertical-align: bottom; " width="35" src="https://upload.wikimedia.org/wikipedia/commons/4/4c/Typescript_logo_2020.svg"> [instantgram] v10.1.2
![GitHub release](https://img.shields.io/badge/release-v10.1.2-green)

![badge](https://img.shields.io/badge/for-instagram-yellow.svg?style=flat-square)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](http://standardjs.com/)
Expand Down Expand Up @@ -39,6 +39,7 @@ With this version we support all modern browsers that have ECMAScript 2015 (es6)
Read [CONTRIBUTING.md](CONTRIBUTING.md) for more information. :heart:

## Changelog
- v10.1.2 - [instangram] Fix issue #17 can't save most types of videos anymore.
- v10.1.1 - [instangram] Fix profile page downloading doesn't work anymore.
- v10.1.0 - [instangram] New image detection algorithm. Image with highest percent in feed and visible in viewport will be grabed by the scanner.
- v10.0.6 - [instangram] Fix #15 Instantgram often grabs avatars/profile pics
Expand Down
2 changes: 1 addition & 1 deletion dist/main.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions index.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lang/de-de/index.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lang/en-us/index.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lang/es-ar/index.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lang/pt-br/index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "instantgram",
"version": "10.1.1",
"version": "10.1.2",
"description": "A bookmarklet for download photos in Instagram",
"author": "Matheus Falcão and from 4.0.0 Sascha Heim",
"homepage": "https://thinkbig-company.github.io/instantgram/",
Expand Down
2 changes: 1 addition & 1 deletion src/_langs/partials/button.html

Large diffs are not rendered by default.

167 changes: 73 additions & 94 deletions src/helpers/getBlobVideoUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,105 +2,84 @@ import getDataFromUrl from './getDataFromUrl'

async function getBlobVideoUrl(el: HTMLVideoElement, article: any, pos: number, callback: any) {

if (Object.keys(el).length > 0) {
const instanceKey = Object.keys(el).find(key => key.includes('Instance'));
/* Will be used only for single video posts */
let isMultiVideo = (pos != null) ? true : false;
if (!isMultiVideo) {
let posterRegex = /poster\=\"([\s\S]*)\" preload/gm;
let posterRegexMatch = posterRegex.exec(el.outerHTML.replace(/(\r\n|\n|\r)/gm, ''));
let videoPosterUrl = null;
if (posterRegexMatch) {
// HACK
let div = document.createElement('textarea');
div.innerHTML = posterRegexMatch[1];
let decoded = div.firstChild.nodeValue;
videoPosterUrl = decoded;
}
var videoPosterFilename = videoPosterUrl.split('/').pop().split('#')[0].split('?')[0];
}

if(article != null && article.length > 0) {
/* Step 1 */
/* Fetch user id from element */
let userId = null;
let userProfileUrl = (article[0].querySelectorAll('header > div > div > div > div > span > a')[0] as HTMLLinkElement).href;

let userProfileUrlResponseData = await getDataFromUrl(userProfileUrl);
if (userProfileUrlResponseData) {
userProfileUrlResponseData = userProfileUrlResponseData.replace(/(\r\n|\n|\r)/gm, '');

if (typeof instanceKey !== 'undefined') {
const reactVideoEl = el[instanceKey];
let m;
let regex = /profilePage_([0-9]+)/gm;
while ((m = regex.exec(userProfileUrlResponseData)) !== null) {
/* This is necessary to avoid infinite loops with zero-width matches */
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}

if (typeof reactVideoEl !== 'undefined') {
const videoUrl = reactVideoEl.return.memoizedProps.fallbackSrc;
/* The result can be accessed through the `m`-variable. */
m.forEach((match) => {
userId = match;
})
}
}

if (typeof videoUrl !== 'undefined') {
callback(videoUrl.length > 0 ? videoUrl : false);
} else {
/* Will be used only for single video posts */
let isMultiVideo = (pos != null) ? true : false;
if (!isMultiVideo) {
let posterRegex = /poster\=\"([\s\S]*)\" preload/gm;
let posterRegexMatch = posterRegex.exec(el.outerHTML.replace(/(\r\n|\n|\r)/gm, ''));
let videoPosterUrl = null;
if (posterRegexMatch) {
// HACK
let div = document.createElement('textarea');
div.innerHTML = posterRegexMatch[1];
let decoded = div.firstChild.nodeValue;
videoPosterUrl = decoded;
}
var videoPosterFilename = videoPosterUrl.split('/').pop().split('#')[0].split('?')[0];
}
/* Step 2 */
/* Fetch the user data until the file name is found */
let videoUrl = null;
if (userId) {
let userMediaFeedResponseData = await getDataFromUrl('https://www.instagram.com/graphql/query/?query_hash=003056d32c2554def87228bc3fd9668a&variables={"id":' + userId + ',"first":100}');
if (userMediaFeedResponseData) {
let json = JSON.parse(userMediaFeedResponseData);

/* Step 1 */
/* Fetch user id from element */
let userId = null;
let userProfileUrl = (article.querySelectorAll('header > div > div > div > span > a')[0] as HTMLLinkElement).href;
let userProfileUrlResponseData = await getDataFromUrl(userProfileUrl);
for (let _fI = 0; _fI < json.data.user.edge_owner_to_timeline_media.edges.length; _fI++) {
if (!isMultiVideo) {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.__typename == 'GraphVideo') {
let GraphVideoNode = json.data.user.edge_owner_to_timeline_media.edges[_fI].node;
if (videoPosterFilename == GraphVideoNode.display_url.split('/').pop().split('#')[0].split('?')[0]) {
videoUrl = GraphVideoNode.video_url;

if (userProfileUrlResponseData) {
userProfileUrlResponseData = userProfileUrlResponseData.replace(/(\r\n|\n|\r)/gm, '');
/* There exists only one node so break it no need to further analyze */
break;
}
}
/* Multi Post which can have a video */
} else {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.__typename == 'GraphSidecar') {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.hasOwnProperty('edge_sidecar_to_children')) {
let GraphSidecarNode = json.data.user.edge_owner_to_timeline_media.edges[_fI].node.edge_sidecar_to_children.edges[pos].node;
videoUrl = GraphSidecarNode.video_url;

let m;
let regex = /profilePage_([0-9]+)/gm;
while ((m = regex.exec(userProfileUrlResponseData)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}

// The result can be accessed through the `m`-variable.
m.forEach((match) => {
userId = match;
})
}
}

/* Step 2 */
/* Fetch the user data until the file name is found */
let videoUrl = null;
if (userId) {
let userMediaFeedResponseData = await getDataFromUrl('https://www.instagram.com/graphql/query/?query_hash=003056d32c2554def87228bc3fd9668a&variables={"id":' + userId + ',"first":100}');
if (userMediaFeedResponseData) {
let json = JSON.parse(userMediaFeedResponseData);

for (let _fI = 0; _fI < json.data.user.edge_owner_to_timeline_media.edges.length; _fI++) {
// Handle different instagram post types
// Single Video
if (!isMultiVideo) {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.__typename == 'GraphVideo') {
let GraphVideoNode = json.data.user.edge_owner_to_timeline_media.edges[_fI].node;
if (videoPosterFilename == GraphVideoNode.display_url.split('/').pop().split('#')[0].split('?')[0]) {
videoUrl = GraphVideoNode.video_url;

// There exists only one node so break it no need to further analyze
break;
}
}
// Multi Post which can have a video
} else {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.__typename == 'GraphSidecar') {
if (json.data.user.edge_owner_to_timeline_media.edges[_fI].node.hasOwnProperty('edge_sidecar_to_children')) {
let GraphSidecarNode = json.data.user.edge_owner_to_timeline_media.edges[_fI].node.edge_sidecar_to_children.edges[pos].node;
videoUrl = GraphSidecarNode.video_url;

break;
}
}
}
}
}
}

callback(videoUrl ? videoUrl : false);
}
} else {
callback(false);
}
} else {
callback(false);
}
} else {
callback(false);
}
break;
}
}
}
}
}
}

callback(videoUrl ? videoUrl : false);
} else {
callback(false);
}
}

export default getBlobVideoUrl;
10 changes: 4 additions & 6 deletions src/modules/MediaScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,9 @@ export class MediaScanner implements Module {
}
}
/*
* For single image
* For single image/video
*/
} else {
let $article: Element | NodeListOf<Element>;

if (isModal) {
$article = document.getElementsByTagName('article')[predictNeededElementIndex];

Expand Down Expand Up @@ -296,13 +294,13 @@ export class MediaScanner implements Module {
$article = $container.querySelectorAll('div > div > article');
}
}

if ($article) {
for (var i = 0; i < ($article as NodeListOf<Element>).length; i++) {
if (getElementPercentage($article[i]) > 50) {
let isVideo = $article[i].querySelector('video') !== null;
let isImage = $article[i].querySelector('.KL4Bh > img[src]') !== null || $article[i].querySelector('.KL4Bh > img[srcset]') !== null;

if (isVideo) {
// Set media type
mediaType = MediaType.Video;
Expand All @@ -326,7 +324,7 @@ export class MediaScanner implements Module {
}
}
}

if (process.env.DEV) {
console.log(['mediaType', mediaType]);
}
Expand Down

0 comments on commit ae1c3cf

Please sign in to comment.