Skip to content

Commit

Permalink
fix: use OneDrive auth when authkey is missing
Browse files Browse the repository at this point in the history
  • Loading branch information
marcomontalbano committed May 14, 2024
1 parent dad30d0 commit 71c59b9
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 13 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Video to Markdown
=================

[![Test](https://github.com/marcomontalbano/video-to-markdown/actions/workflows/test.yaml/badge.svg)](https://github.com/marcomontalbano/video-to-markdown/actions/workflows/test.yaml)
[![Cloudinary](https://shields.io/badge/-Cloudinary-3448c5)](https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq)
[![Cloudinary](https://shields.io/badge/-Cloudinary-3448c5)](https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq?t=default)
[![PayPal.me](https://img.shields.io/badge/paypal-donate-119fde.svg)](https://www.paypal.me/marcomontalbano)
[![Sponsor](https://img.shields.io/badge/-Sponsor-fafbfc?logo=GitHub%20Sponsors)](https://github.com/sponsors/marcomontalbano)

Expand Down Expand Up @@ -110,4 +110,4 @@ In this way the generated images are cached so we can avoid to call Netlify func

By clicking on `convert to markdown` or consuming api you accept this terms & condition; no additional data is sent to the server.

[Cloudinary]: https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq
[Cloudinary]: https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq?t=default
95 changes: 86 additions & 9 deletions netlify/functions/classes/Providers/OneDrive.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,103 @@ export default class OneDrive extends VideoProvider {
return [
// - //1drv.ms/v/s!An21T-lhvYKSkFpqKTb4YeZpKfzC?e=iXCxja
/https?\:\/\/1drv\.ms\/[\w]{1}\/s!([a-zA-Z0-9-]+)/,

// - //1drv.ms/v/c/1c827834532d42r1/ETAjK46wOQhKve5q-SzK5kMBvglqiXaAOVnbr7H2Phvve3?e=Qblvee
/https?\:\/\/1drv\.ms\/[\w]{1}\/[\w]{1}\/([a-zA-Z0-9]+\/[a-zA-Z0-9-]+)/,
];
}

getThumbnail_asVideoUrl() {
return fetch(this.url)
.then((response) => response.url)
.then((redirectUrl) => {
.then(async (response) => ({
url: response.url,
text: await response.text(),
}))
.then(async ({ url: redirectUrl, text }) => {
this.log('redirectUrl', redirectUrl);

const searchParams = new URL(redirectUrl).searchParams;

// GET /drives/{drive-id}/items/{item-id}/thumbnails
const driveId = searchParams.get('cid');
const itemId = searchParams.get('resId');
const authkey = searchParams.get('authkey');
const redeem = searchParams.get('redeem');

if (driveId == null || itemId == null || authkey == null) {
if (driveId == null || itemId == null || (authkey == null && redeem == null)) {
throw new Error('Link is not valid.');
}

// https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_thumbnails?view=odsp-graph-online
const apiUrl = `https://api.onedrive.com/v1.0/drives/${driveId}/items/${itemId}/thumbnails?authkey=${authkey}`;
this.log('apiUrl', apiUrl);
return fetch(apiUrl);
this.log('driveId', driveId);
this.log('itemId', itemId);

if (authkey != null) {
this.log('auth', 'authkey is defined');
// https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_thumbnails?view=odsp-graph-online
const apiUrl = `https://api.onedrive.com/v1.0/drives/${driveId}/items/${itemId}/thumbnails?authkey=${authkey}`;
this.log('apiUrl', apiUrl);

return fetch(apiUrl);
}

if (redeem != null) {
this.log('auth', 'authentication required');
const [, appId] = text.match(/"clientId":"([\w-]+)"/);
this.log('appId', appId);
const auth = await fetch('https://api-badgerp.svc.ms/v1.0/token', {
headers: {
accept: '*/*',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'private',
'content-type': 'application/json;odata=verbose',
priority: 'u=1, i',
'sec-ch-ua': '"Not-A.Brand";v="99", "Chromium";v="124"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'cross-site',
},
referrer: 'https://photos.onedrive.com/',
referrerPolicy: 'strict-origin-when-cross-origin',
body: JSON.stringify({ appId }),
method: 'POST',
mode: 'cors',
credentials: 'omit',
}).then((r) => r.json());

const { authScheme, token } = auth;

if (authScheme == null || token == null) {
throw new Error('Cannot get a valid token.');
}

// https://learn.microsoft.com/en-us/onedrive/developer/rest-api/resources/driveitem?view=odsp-graph-online
const apiUrl = `https://my.microsoftpersonalcontent.com/_api/v2.0/shares/u!${redeem}/driveitem/thumbnails`;
this.log('apiUrl', apiUrl);

return fetch(apiUrl, {
headers: {
accept: '*/*',
'accept-language': 'en-US,en;q=0.9',
authorization: `${capitalizeFirstLetter(authScheme)} ${token}`,
'cache-control': 'max-age=0',
'content-type': 'text/plain;charset=UTF-8',
prefer: 'autoredeem',
priority: 'u=1, i',
'sec-ch-ua': '"Not-A.Brand";v="99", "Chromium";v="124"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'cross-site',
},
referrer: 'https://photos.onedrive.com/',
referrerPolicy: 'strict-origin-when-cross-origin',
body: null,
method: 'POST',
mode: 'cors',
credentials: 'include',
});
}
})
.then((res) => res.json())
.then((json) => {
Expand All @@ -58,3 +131,7 @@ export default class OneDrive extends VideoProvider {
});
}
}

function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
8 changes: 7 additions & 1 deletion netlify/functions/classes/VideoProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ export default class VideoProvider {
}

static getVideoId(url = '') {
return this.regex
const id = this.regex
.map((rx) => {
let [, id] = url.match(rx) || [];
return id;
})
.filter((id) => id)[0];

if (typeof id === 'string') {
return id.replaceAll('/', '--');
}

return id;
}

needsCloudinary() {
Expand Down
1 change: 1 addition & 0 deletions netlify/functions/image-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const handler = async (event, context, callback) => {

video.log('httpMethod', event.httpMethod);
video.log('url', url);
video.log('id', video.getId());
video.log('highQuality', cloudinary.useHighQuality() ? 'true' : 'false');

return video
Expand Down
2 changes: 1 addition & 1 deletion src/web/_disclaimer.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h2>Disclaimer</h2>
<p>
This is an open source project with no sponsor (yet).
Images are generated via <a target="_blank" rel="noopener noreferrer" href="https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq">Cloudinary</a> and stored in it thus reducing <a target="_blank" rel="noopener noreferrer" href="https://www.netlify.com/">Netlify</a> quota consumption.
Images are generated via <a target="_blank" rel="noopener noreferrer" href="https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/nfvt85kdqleszdah0hxq?t=default">Cloudinary</a> and stored in it thus reducing <a target="_blank" rel="noopener noreferrer" href="https://www.netlify.com/">Netlify</a> quota consumption.
I'm trying doing my best using free services which I cannot guarantee will always be 100% up and running.
To be totally safe, I suggest you generate the video image and download it, storing it directly into your repository or server.
Otherwise you can host <a class="host" target="_blank" rel="noopener noreferrer" href="https://github.com/marcomontalbano/video-to-markdown#hosting">your own copy <img alt="netlify"
Expand Down

0 comments on commit 71c59b9

Please sign in to comment.