Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removerecommend #8

Merged
merged 8 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
coverage
.env

.DS_Store
.DS_Store
dist
3 changes: 2 additions & 1 deletion dist/features/FeatureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class FeatureStorage extends Storage_1.default {
return topReblogs;
}
else {
const reblogs = await (0, reblogsFeature_1.default)(api);
const user = await this.getIdentity();
const reblogs = await (0, reblogsFeature_1.default)(api, user);
await this.set(Storage_1.Key.TOP_REBLOGS, reblogs);
return reblogs;
}
Expand Down
12 changes: 6 additions & 6 deletions dist/features/coreServerFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ async function coreServerFeature(api, user) {
return accumulator;
}, {});
console.log(serverFrequ);
// for top 30 servers
const top30 = Object.keys(serverFrequ).sort((a, b) => serverFrequ[b] - serverFrequ[a]).slice(0, 30);
console.log("Top 30 servers: ", top30);
const monthlyUsers = await Promise.all(top30.map(server => getMonthlyUsers(server)));
// for top 20 servers
const top20 = Object.keys(serverFrequ).sort((a, b) => serverFrequ[b] - serverFrequ[a]).slice(0, 30);
console.log("Top 30 servers: ", top20);
const monthlyUsers = await Promise.all(top20.map(server => getMonthlyUsers(server)));
console.log("Monthly Users: ", monthlyUsers);
const overrepresentedServerFrequ = top30.reduce((acc, server, index) => {
const overrepresentedServerFrequ = top20.reduce((acc, server, index) => {
const activeUsers = monthlyUsers[index];
if (activeUsers < 1)
if (activeUsers < 10)
return acc;
const ratio = serverFrequ[server] / activeUsers;
return { ...acc, [server]: ratio };
Expand Down
2 changes: 1 addition & 1 deletion dist/features/reblogsFeature.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import { mastodon } from "masto";
export default function getReblogsFeature(api: mastodon.rest.Client): Promise<Record<string, number>>;
export default function getReblogsFeature(api: mastodon.rest.Client, user: mastodon.v1.Account): Promise<Record<string, number>>;
6 changes: 4 additions & 2 deletions dist/features/reblogsFeature.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
async function getReblogsFeature(api) {
async function getReblogsFeature(api, user) {
let results = [];
let pages = 3;
try {
for await (const page of api.v1.timelines.home.list({ limit: 80 })) {
for await (const page of api.v1.accounts.$select(user.id).statuses.list({ limit: 80 })) {
results = results.concat(page);
pages--;
if (pages === 0 || results.length < 80) {
Expand All @@ -16,6 +16,7 @@ async function getReblogsFeature(api) {
console.error(e);
return {};
}
console.log(results);
const reblogFrequ = results.reduce((accumulator, status) => {
if (status.reblog) {
if (status.reblog.account.acct in accumulator) {
Expand All @@ -27,6 +28,7 @@ async function getReblogsFeature(api) {
}
return accumulator;
}, {});
console.log(reblogFrequ);
return reblogFrequ;
}
exports.default = getReblogsFeature;
12 changes: 9 additions & 3 deletions dist/feeds/topPostsFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ async function getTopPostFeed(api) {
results = await Promise.all(servers.map(async (server) => {
if (server === "undefined" || typeof server == "undefined" || server === "")
return [];
const data = await (0, helpers_1.mastodonFetch)(server, "api/v1/timelines/public");
return data?.map((status) => {
const data = await (0, helpers_1.mastodonFetch)(server, "api/v1/trends/statuses");
return data?.filter(status => status?.favouritesCount > 0 || status?.reblogsCount > 0).map((status) => {
status.topPost = true;
return status;
}).slice(0, 10) ?? [];
}));
console.log(results);
const lastOpened = new Date((await Storage_1.default.getLastOpened() ?? 0) - 28800000);
return results.flat().filter((status) => new Date(status.createdAt) > lastOpened);
return results.flat().filter((status) => new Date(status.createdAt) > lastOpened).map((status) => {
const acct = status.account.acct;
if (acct && !acct.includes("@")) {
status.account.acct = `${acct}@${status.account.url.split("/")[2]}`;
}
return status;
});
}
exports.default = getTopPostFeed;
16 changes: 11 additions & 5 deletions dist/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ const _transformKeys = (data, transform) => {
};
exports._transformKeys = _transformKeys;
const mastodonFetch = async (server, endpoint) => {
const json = await axios_1.default.get(`https://${server}${endpoint}`);
if (!(json.status === 200) || !json.data) {
console.error(`Error fetching data for server ${server}:`, json);
try {
const json = await axios_1.default.get(`https://${server}${endpoint}`);
if (!(json.status === 200) || !json.data) {
console.error(`Error fetching data for server ${server}:`, json);
return;
}
const data = (0, exports._transformKeys)(json.data, change_case_1.camelCase);
return data;
}
catch (error) {
console.error(`Error fetching data for server ${server}:`, error);
return;
}
const data = (0, exports._transformKeys)(json.data, change_case_1.camelCase);
return data;
};
exports.mastodonFetch = mastodonFetch;
2 changes: 1 addition & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class TheAlgorithm {
// Add Time Penalty
scoredFeed = scoredFeed.map((item) => {
const seconds = Math.floor((new Date().getTime() - new Date(item.createdAt).getTime()) / 1000);
const timediscount = Math.pow((1 + 0.7 * 0.2), -Math.pow((seconds / 3600), 2));
const timediscount = Math.pow((1 + 0.05), -Math.pow((seconds / 3600), 2));
item.value = (item.value ?? 0) * timediscount;
return item;
});
Expand Down
12 changes: 6 additions & 6 deletions dist/scorer/feed/reblogsFeedScorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ class reblogsFeedScorer extends FeedScorer_1.default {
super("reblogsFeed", "More Weight to posts that are reblogged a lot", 6);
}
feedExtractor(feed) {
return feed.reduce((obj, status) => {
// for each uri in the feed, count the number of times it appears
const feedScorer = feed.reduce((obj, status) => {
obj[status.uri] = (obj[status.uri] || 0) + 1;
if (status.reblog) {
obj[status.reblog.uri] = (obj[status.reblog.uri] || -1) + 1;
}
else {
obj[status.uri] = (obj[status.uri] || -1) + 1;
obj[status.reblog.uri] = (obj[status.reblog.uri] || 0) + 1;
}
return obj;
}, {});
return feedScorer;
}
async score(status) {
super.score(status);
const features = this.features;
if (status.reblog) {
return features[status.reblog.uri] || 0;
}
return 0;
return features[status.uri] || 0;
}
}
exports.default = reblogsFeedScorer;
3 changes: 2 additions & 1 deletion src/features/FeatureStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export default class FeatureStorage extends Storage {
if (topReblogs != null && await this.getOpenings() % 10 < 9) {
return topReblogs;
} else {
const reblogs = await reblogsFeature(api);
const user = await this.getIdentity()
const reblogs = await reblogsFeature(api, user);
await this.set(Key.TOP_REBLOGS, reblogs);
return reblogs;
}
Expand Down
12 changes: 6 additions & 6 deletions src/features/coreServerFeature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ export default async function coreServerFeature(api: mastodon.rest.Client, user:

console.log(serverFrequ)

// for top 30 servers
const top30 = Object.keys(serverFrequ).sort((a, b) => serverFrequ[b] - serverFrequ[a]).slice(0, 30)
// for top 20 servers
const top20 = Object.keys(serverFrequ).sort((a, b) => serverFrequ[b] - serverFrequ[a]).slice(0, 30)

console.log("Top 30 servers: ", top30)
const monthlyUsers = await Promise.all(top30.map(server => getMonthlyUsers(server)))
console.log("Top 30 servers: ", top20)
const monthlyUsers = await Promise.all(top20.map(server => getMonthlyUsers(server)))

console.log("Monthly Users: ", monthlyUsers)

const overrepresentedServerFrequ = top30.reduce((acc, server, index) => {
const overrepresentedServerFrequ = top20.reduce((acc, server, index) => {
const activeUsers = monthlyUsers[index];
if (activeUsers < 1) return acc;
if (activeUsers < 10) return acc;
const ratio = serverFrequ[server] / activeUsers;
return { ...acc, [server]: ratio }
}, {})
Expand Down
7 changes: 4 additions & 3 deletions src/features/reblogsFeature.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { mastodon } from "masto";

export default async function getReblogsFeature(api: mastodon.rest.Client) {
export default async function getReblogsFeature(api: mastodon.rest.Client, user: mastodon.v1.Account): Promise<Record<string, number>> {
let results: mastodon.v1.Status[] = [];
let pages = 3;
try {
for await (const page of api.v1.timelines.home.list({ limit: 80 })) {
for await (const page of api.v1.accounts.$select(user.id).statuses.list({ limit: 80 })) {
results = results.concat(page)
pages--;
if (pages === 0 || results.length < 80) {
Expand All @@ -15,6 +15,7 @@ export default async function getReblogsFeature(api: mastodon.rest.Client) {
console.error(e)
return {};
}
console.log(results)

const reblogFrequ = results.reduce((accumulator: Record<string, number>, status: mastodon.v1.Status) => {
if (status.reblog) {
Expand All @@ -26,6 +27,6 @@ export default async function getReblogsFeature(api: mastodon.rest.Client) {
}
return accumulator
}, {})

console.log(reblogFrequ)
return reblogFrequ;
}
14 changes: 11 additions & 3 deletions src/feeds/topPostsFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,22 @@ export default async function getTopPostFeed(api: mastodon.rest.Client): Promise
results = await Promise.all(servers.map(async (server: string): Promise<StatusType[]> => {
if (server === "undefined" || typeof server == "undefined" || server === "") return [];

const data = await mastodonFetch<StatusType[]>(server, "api/v1/timelines/public")
return data?.map((status: StatusType) => {
const data = await mastodonFetch<StatusType[]>(server, "api/v1/trends/statuses")
return data?.filter(
status => status?.favouritesCount > 0 || status?.reblogsCount > 0
).map((status: StatusType) => {
status.topPost = true;
return status;
}).slice(0, 10) ?? []
}))
console.log(results)

const lastOpened = new Date((await Storage.getLastOpened() ?? 0) - 28800000)
return results.flat().filter((status: StatusType) => new Date(status.createdAt) > lastOpened)
return results.flat().filter((status: StatusType) => new Date(status.createdAt) > lastOpened).map((status: StatusType) => {
const acct = status.account.acct
if (acct && !acct.includes("@")) {
status.account.acct = `${acct}@${status.account.url.split("/")[2]}`
}
return status
})
}
15 changes: 10 additions & 5 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ export const _transformKeys = <T>(
};

export const mastodonFetch = async <T>(server: string, endpoint: string): Promise<T | undefined> => {
const json = await axios.get<T>(`https://${server}${endpoint}`)
if (!(json.status === 200) || !json.data) {
console.error(`Error fetching data for server ${server}:`, json);
try {
const json = await axios.get<T>(`https://${server}${endpoint}`)
if (!(json.status === 200) || !json.data) {
console.error(`Error fetching data for server ${server}:`, json);
return
}
const data: T = _transformKeys(json.data, camelCase)
return data;
} catch (error) {
console.error(`Error fetching data for server ${server}:`, error);
return
}
const data: T = _transformKeys(json.data, camelCase)
return data;
}
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export default class TheAlgorithm {
// Load Scores for each status
const featureScore = await Promise.all(featureScorer.map(scorer => scorer.score(this.api, status)));
const feedScore = await Promise.all(feedScorer.map(scorer => scorer.score(status)));

// Turn Scores into Weight Objects
const featureScoreObj = this._getScoreObj(scoreNames, featureScore);
const feedScoreObj = this._getScoreObj(feedScoreNames, feedScore);
Expand All @@ -97,7 +96,7 @@ export default class TheAlgorithm {
// Add Time Penalty
scoredFeed = scoredFeed.map((item: StatusType) => {
const seconds = Math.floor((new Date().getTime() - new Date(item.createdAt).getTime()) / 1000);
const timediscount = Math.pow((1 + 0.7 * 0.2), - Math.pow((seconds / 3600), 2));
const timediscount = Math.pow((1 + 0.05), - Math.pow((seconds / 3600), 2));
item.value = (item.value ?? 0) * timediscount
return item;
})
Expand Down
11 changes: 6 additions & 5 deletions src/scorer/feed/reblogsFeedScorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ export default class reblogsFeedScorer extends FeedScorer {
}

feedExtractor(feed: StatusType[]) {
return feed.reduce((obj: Record<string, number>, status) => {
// for each uri in the feed, count the number of times it appears
const feedScorer = feed.reduce((obj: Record<string, number>, status: StatusType) => {
obj[status.uri] = (obj[status.uri] || 0) + 1;
if (status.reblog) {
obj[status.reblog.uri] = (obj[status.reblog.uri] || -1) + 1;
} else {
obj[status.uri] = (obj[status.uri] || -1) + 1;
obj[status.reblog.uri] = (obj[status.reblog.uri] || 0) + 1;
}
return obj;
}, {});
return feedScorer;
}

async score(status: StatusType) {
Expand All @@ -23,6 +24,6 @@ export default class reblogsFeedScorer extends FeedScorer {
if (status.reblog) {
return features[status.reblog.uri] || 0;
}
return 0;
return features[status.uri] || 0;
}
}