Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videostreaming/plugins/dailymotion
1 result
Show changes
Commits on Source (7)
stages:
- deploy
- deploy
deploy:
deploy-master:
stage: deploy
script:
- export PRE_RELEASE=false
- sh deploy.sh
only:
- master
deploy-dev:
stage: deploy
script:
- export PRE_RELEASE=true
- sh deploy.sh
only:
- dev
......@@ -7,7 +7,7 @@
"sourceUrl": "https://plugins.grayjay.app/Dailymotion/DailymotionConfig.json",
"scriptUrl": "./DailymotionScript.js",
"repositoryUrl": "https://futo.org",
"version": 23,
"version": 26,
"iconUrl": "./DailymotionIcon.png",
"id": "9c87e8db-e75d-48f4-afe5-2d203d4b95c5",
"scriptSignature": "",
......
......@@ -7,7 +7,7 @@
"sourceUrl": "https://plugins.grayjay.app/Dailymotion/DailymotionConfig.json",
"scriptUrl": "./DailymotionScript.js",
"repositoryUrl": "https://futo.org",
"version": 23,
"version": 26,
"iconUrl": "./DailymotionIcon.png",
"id": "9c87e8db-e75d-48f4-afe5-2d203d4b95c5",
"scriptSignature": "",
......
......@@ -1157,6 +1157,9 @@ function generateUUIDv4() {
function applyCommonHeaders(headers = {}) {
return { ...DEFAULT_HEADERS, ...headers };
}
function notifyMaintenanceMode() {
bridge.toast('Dailymotion is currently offline for maintenance. Thanks for your patience.');
}
class SearchPagerAll extends VideoPager {
cb;
......@@ -1471,11 +1474,7 @@ function oauthClientCredentialsRequest(httpClient, url, clientId, secret, throwO
return null;
}
}
function extractClientCredentials(httpClient) {
const detailsRequestHtml = httpClient.GET(BASE_URL, {}, false);
if (!detailsRequestHtml.isOk) {
throw new ScriptException('Failed to fetch page to extract auth details');
}
function extractClientCredentials(detailsRequestHtml) {
const result = [];
const match = detailsRequestHtml.body.match(REGEX_INITIAL_DATA_API_AUTH_1);
if (match?.length === 2 && match[0] && match[1]) {
......@@ -1553,7 +1552,8 @@ const state = {
anonymousUserAuthorizationToken: '',
anonymousUserAuthorizationTokenExpirationDate: 0,
commentWebServiceToken: '',
channelsCache: {}
channelsCache: {},
maintenanceMode: false
};
source.setSettings = function (settings) {
_settings = settings;
......@@ -1625,7 +1625,27 @@ source.enable = function (conf, settings, saveStateStr) {
if (IS_TESTING) {
log('Getting a new tokens');
}
const clientCredentials = extractClientCredentials(http);
let detailsRequestHtml;
try {
detailsRequestHtml = http.GET(BASE_URL, applyCommonHeaders(), false);
if (!detailsRequestHtml.isOk) {
if (detailsRequestHtml.code >= 500 && detailsRequestHtml.code < 600) {
state.maintenanceMode = true;
notifyMaintenanceMode();
}
else {
throw new ScriptException('Failed to fetch page to extract auth details');
}
return;
}
}
catch (e) {
state.maintenanceMode = true;
notifyMaintenanceMode();
return;
}
state.maintenanceMode = false;
const clientCredentials = extractClientCredentials(detailsRequestHtml);
const { anonymousUserAuthorizationToken, anonymousUserAuthorizationTokenExpirationDate, isValid, } = getTokenFromClientCredentials(http, clientCredentials);
if (!isValid) {
console.error('Failed to get token');
......@@ -1655,6 +1675,9 @@ source.enable = function (conf, settings, saveStateStr) {
}
};
source.getHome = function () {
if (state.maintenanceMode) {
return new ContentPager([]);
}
return getHomePager({}, 0);
};
source.searchSuggestions = function (query) {
......@@ -1704,6 +1727,9 @@ source.getChannel = function (url) {
return state.channelsCache[url];
};
source.getChannelContents = function (url, type, order, filters) {
if (state.maintenanceMode) {
return new ContentPager([]);
}
const page = 1;
return getChannelContentsPager(url, page, type, order, filters);
};
......@@ -2055,9 +2081,9 @@ function getChannelContentsPager(url, page, type, order, filters) {
log(`Getting channel contents for ${url}, page: ${page}, type: ${type}, order: ${order}, shouldLoadVideos: ${shouldLoadVideos}, shouldLoadLives: ${shouldLoadLives}, filters: ${JSON.stringify(filters)}`);
}
/**
Recent = Sort liked medias by most recent.
Visited - Sort liked medias by most viewed
*/
Recent = Sort liked medias by most recent.
Visited - Sort liked medias by most viewed
*/
let sort;
if (order == Type.Order.Chronological) {
sort = LikedMediaSort.Recent;
......
#!/bin/sh
DOCUMENT_ROOT=/var/www/sources
# Use environment variable to determine deployment type
PRE_RELEASE=${PRE_RELEASE:-false} # Default to false if not set
# Determine deployment directory
if [ "$PRE_RELEASE" = "true" ]; then
RELATIVE_PATH="pre-release/Dailymotion"
else
RELATIVE_PATH="Dailymotion"
fi
DEPLOY_DIR="$DOCUMENT_ROOT/$RELATIVE_PATH"
PLUGIN_URL_ROOT="https://plugins.grayjay.app/$RELATIVE_PATH"
SOURCE_URL="$PLUGIN_URL_ROOT/DailymotionConfig.json"
# Take site offline
echo "Taking site offline..."
touch $DOCUMENT_ROOT/maintenance.file
# Swap over the content
echo "Deploying content..."
mkdir -p $DOCUMENT_ROOT/Dailymotion
cp build/DailymotionIcon.png $DOCUMENT_ROOT/Dailymotion
cp build/DailymotionConfig.json $DOCUMENT_ROOT/Dailymotion
cp build/DailymotionScript.js $DOCUMENT_ROOT/Dailymotion
sh sign.sh $DOCUMENT_ROOT/Dailymotion/DailymotionScript.js $DOCUMENT_ROOT/Dailymotion/DailymotionConfig.json
mkdir -p "$DEPLOY_DIR"
cp build/DailymotionIcon.png "$DEPLOY_DIR"
cp build/DailymotionConfig.json "$DEPLOY_DIR"
cp build/DailymotionScript.js "$DEPLOY_DIR"
# Update the sourceUrl in DailymotionConfig.json
echo "Updating sourceUrl in DailymotionConfig.json..."
jq --arg sourceUrl "$SOURCE_URL" '.sourceUrl = $sourceUrl' "$DEPLOY_DIR/DailymotionConfig.json" > "$DEPLOY_DIR/DailymotionConfig_temp.json"
if [ $? -eq 0 ]; then
mv "$DEPLOY_DIR/DailymotionConfig_temp.json" "$DEPLOY_DIR/DailymotionConfig.json"
else
echo "Failed to update DailymotionConfig.json" >&2
exit 1
fi
sh sign.sh "$DEPLOY_DIR/DailymotionScript.js" "$DEPLOY_DIR/DailymotionConfig.json"
# Notify Cloudflare to wipe the CDN cache
echo "Purging Cloudflare cache for zone $CLOUDFLARE_ZONE_ID..."
curl -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://plugins.grayjay.app/Dailymotion/DailymotionIcon.png", "https://plugins.grayjay.app/Dailymotion/DailymotionConfig.json", "https://plugins.grayjay.app/Dailymotion/DailymotionScript.js"]}'
--data '{"files":["'"$PLUGIN_URL_ROOT/DailymotionIcon.png"'", "'"$PLUGIN_URL_ROOT/DailymotionConfig.json"'", "'"$PLUGIN_URL_ROOT/DailymotionScript.js"'"]}'
# Take site back online
echo "Bringing site back online..."
rm $DOCUMENT_ROOT/maintenance.file
rm "$DOCUMENT_ROOT/maintenance.file"
......@@ -5,7 +5,8 @@ const state = {
anonymousUserAuthorizationToken: '',
anonymousUserAuthorizationTokenExpirationDate: 0,
commentWebServiceToken: '',
channelsCache: {} as Record<string, PlatformChannel>
channelsCache: {} as Record<string, PlatformChannel>,
maintenanceMode: false
};
import {
......@@ -52,7 +53,13 @@ import {
playerVideosDataQuery,
} from './gqlQueries';
import { getChannelNameFromUrl, getQuery, generateUUIDv4, applyCommonHeaders } from './util';
import {
getChannelNameFromUrl,
getQuery,
generateUUIDv4,
applyCommonHeaders,
notifyMaintenanceMode
} from './util';
import {
Channel,
......@@ -155,10 +162,10 @@ source.enable = function (conf, settings, saveStateStr) {
if (saveState) {
Object
.keys(state)
.forEach((key) => {
state[key] = saveState[key];
});
.keys(state)
.forEach((key) => {
state[key] = saveState[key];
});
if (!isTokenValid()) {
log('Token expired. Fetching a new one.');
......@@ -178,7 +185,30 @@ source.enable = function (conf, settings, saveStateStr) {
log('Getting a new tokens');
}
const clientCredentials = extractClientCredentials(http);
let detailsRequestHtml;
try {
detailsRequestHtml = http.GET(BASE_URL, applyCommonHeaders(), false);
if (!detailsRequestHtml.isOk) {
if (detailsRequestHtml.code >= 500 && detailsRequestHtml.code < 600) {
state.maintenanceMode = true;
notifyMaintenanceMode();
} else {
throw new ScriptException('Failed to fetch page to extract auth details');
}
return;
}
} catch(e) {
state.maintenanceMode = true;
notifyMaintenanceMode();
return;
}
state.maintenanceMode = false;
const clientCredentials = extractClientCredentials(detailsRequestHtml);
const {
anonymousUserAuthorizationToken,
......@@ -210,11 +240,11 @@ source.enable = function (conf, settings, saveStateStr) {
}),
false,
);
if (!authenticateIm.isOk) {
log('Failed to authenticate to comments service');
}
state.commentWebServiceToken = authenticateIm?.headers?.['x-access-token']?.[0];
} catch (error) {
log('Failed to authenticate to comments service:' + error);
......@@ -224,6 +254,11 @@ source.enable = function (conf, settings, saveStateStr) {
};
source.getHome = function () {
if (state.maintenanceMode) {
return new ContentPager([]);
}
return getHomePager({}, 0);
};
......@@ -293,6 +328,11 @@ source.getChannel = function (url) {
};
source.getChannelContents = function (url, type, order, filters) {
if (state.maintenanceMode) {
return new ContentPager([]);
}
const page = 1;
return getChannelContentsPager(url, page, type, order, filters);
};
......@@ -433,8 +473,8 @@ class PlatformCommentPager extends CommentPager {
source.isPlaylistUrl = (url): boolean => {
return (
REGEX_VIDEO_PLAYLIST_URL.test(url) || [
LIKED_VIDEOS_PLAYLIST_ID,
FAVORITE_VIDEOS_PLAYLIST_ID,
LIKED_VIDEOS_PLAYLIST_ID,
FAVORITE_VIDEOS_PLAYLIST_ID,
RECENTLY_WATCHED_VIDEOS_PLAYLIST_ID
].includes(url)
);
......@@ -582,11 +622,11 @@ source.getUserPlaylists = (): string[] => {
FAVORITE_VIDEOS_PLAYLIST_ID,
RECENTLY_WATCHED_VIDEOS_PLAYLIST_ID,
]
.forEach((playlistId) => {
if (!playlists.includes(playlistId)) {
playlists.push(playlistId);
}
});
.forEach((playlistId) => {
if (!playlists.includes(playlistId)) {
playlists.push(playlistId);
}
});
return playlists;
};
......@@ -600,7 +640,7 @@ source.getChannelTemplateByClaimMap = () => {
};
};
source.getContentRecommendations = (url, initialData) => {
source.getContentRecommendations = (url, initialData) => {
try {
const videoXid = url.split('/').pop();
......@@ -614,9 +654,9 @@ source.getContentRecommendations = (url, initialData) => {
query: DISCOVERY_QUEUE_QUERY,
usePlatformAuth: false,
});
const videoXids: string[] = gqlResponse?.data?.views?.neon?.sections?.edges?.[0]?.node?.components?.edges?.map(e => e.node.xid) ?? [];
const gqlResponse1 = executeGqlQuery(http, {
operationName: 'playerVideosDataQuery',
variables: {
......@@ -628,14 +668,14 @@ source.getContentRecommendations = (url, initialData) => {
query: playerVideosDataQuery,
usePlatformAuth: false,
});
const results =
gqlResponse1.data.videos.edges
gqlResponse1.data.videos.edges
?.map((edge) => {
return SourceVideoToGrayjayVideo(config.id, edge.node as Video);
});
return new VideoPager(results, false);
} catch(error){
log('Failed to get recommendations:' + error);
......@@ -667,9 +707,9 @@ function getPlaylistsByUsername(
const playlists: string[] = (collections.data.channel as Maybe<Channel>)?.collections?.edges?.map(
(edge) => {
let playlistUrl = `${BASE_URL_PLAYLIST}/${edge?.node?.xid}`;
const isPrivatePlaylist = edge?.node?.isPrivate ?? false;
if(isPrivatePlaylist){
......@@ -801,9 +841,9 @@ function getChannelContentsPager(url, page, type, order, filters) {
}
/**
Recent = Sort liked medias by most recent.
Visited - Sort liked medias by most viewed
*/
Recent = Sort liked medias by most recent.
Visited - Sort liked medias by most viewed
*/
let sort: string;
if (order == Type.Order.Chronological) {
......
......@@ -6,7 +6,7 @@ import {
REGEX_INITIAL_DATA_API_AUTH_1,
USER_AGENT,
} from './constants';
import { objectToUrlEncodedString } from './util';
import { objectToUrlEncodedString, applyCommonHeaders } from './util';
export function oauthClientCredentialsRequest(
httpClient: IHttp,
......@@ -56,12 +56,7 @@ export function oauthClientCredentialsRequest(
}
}
export function extractClientCredentials(httpClient: IHttp) {
const detailsRequestHtml = httpClient.GET(BASE_URL, {}, false);
if (!detailsRequestHtml.isOk) {
throw new ScriptException('Failed to fetch page to extract auth details');
}
export function extractClientCredentials(detailsRequestHtml) {
const result = [];
......
......@@ -119,4 +119,8 @@ export function generateUUIDv4() {
export function applyCommonHeaders(headers: Record<string, string>={}) : Record<string, string>{
return { ...DEFAULT_HEADERS, ...headers };
}
export function notifyMaintenanceMode() {
bridge.toast('Dailymotion is currently offline for maintenance. Thanks for your patience.');
}
\ No newline at end of file