or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blog-content.mdclient-configuration.mdcontent-discovery.mdhttp-requests.mdindex.mdpost-management.mdsocial-interactions.mduser-management.md

social-interactions.mddocs/

0

# Social Interactions

1

2

Like, unlike, follow, and unfollow functionality for social engagement on the Tumblr platform.

3

4

## Capabilities

5

6

### Like Post

7

8

Like a specific post as the authenticated user.

9

10

```javascript { .api }

11

/**

12

* Like a post as the authenticating user

13

* @param postId - ID of the post to like

14

* @param reblogKey - Reblog key of the post to like

15

* @returns Promise resolving to like confirmation

16

*/

17

likePost(postId: string, reblogKey: string): Promise<any>;

18

```

19

20

**Usage Examples:**

21

22

```javascript

23

// Like a post (requires post ID and reblog key from post data)

24

await client.likePost('12345', 'abc123def456');

25

console.log('Post liked successfully');

26

27

// Get post data first, then like it

28

const posts = await client.blogPosts('some-blog');

29

const firstPost = posts.posts[0];

30

await client.likePost(firstPost.id, firstPost.reblog_key);

31

```

32

33

### Unlike Post

34

35

Remove a like from a post as the authenticated user.

36

37

```javascript { .api }

38

/**

39

* Unlike a post as the authenticating user

40

* @param postId - ID of the post to unlike

41

* @param reblogKey - Reblog key of the post to unlike

42

* @returns Promise resolving to unlike confirmation

43

*/

44

unlikePost(postId: string, reblogKey: string): Promise<any>;

45

```

46

47

**Usage Examples:**

48

49

```javascript

50

// Unlike a previously liked post

51

await client.unlikePost('12345', 'abc123def456');

52

console.log('Post unliked successfully');

53

54

// Unlike posts from your likes list

55

const likes = await client.userLikes({ limit: 5 });

56

for (const post of likes.liked_posts) {

57

await client.unlikePost(post.id, post.reblog_key);

58

console.log(`Unliked post ${post.id}`);

59

}

60

```

61

62

### Follow Blog

63

64

Follow a blog as the authenticated user.

65

66

```javascript { .api }

67

/**

68

* Follow a blog as the authenticating user

69

* @param params - Blog identification parameters

70

* @returns Promise resolving to follow confirmation

71

*/

72

followBlog(params: { url: string } | { email: string }): Promise<any>;

73

```

74

75

**Usage Examples:**

76

77

```javascript

78

// Follow a blog by URL

79

await client.followBlog({ url: 'cool-blog.tumblr.com' });

80

console.log('Blog followed successfully');

81

82

// Follow a blog by full URL

83

await client.followBlog({ url: 'https://cool-blog.tumblr.com/' });

84

85

// Follow a blog by email (if supported)

86

await client.followBlog({ email: 'blogger@example.com' });

87

88

// Follow multiple blogs

89

const blogsToFollow = [

90

'photography-blog.tumblr.com',

91

'art-blog.tumblr.com',

92

'music-blog.tumblr.com'

93

];

94

95

for (const blogUrl of blogsToFollow) {

96

try {

97

await client.followBlog({ url: blogUrl });

98

console.log(`Followed ${blogUrl}`);

99

} catch (error) {

100

console.error(`Failed to follow ${blogUrl}:`, error.message);

101

}

102

}

103

```

104

105

### Unfollow Blog

106

107

Unfollow a blog as the authenticated user.

108

109

```javascript { .api }

110

/**

111

* Unfollow a blog as the authenticating user

112

* @param params - Blog URL to unfollow

113

* @returns Promise resolving to unfollow confirmation

114

*/

115

unfollowBlog(params: { url: string }): Promise<any>;

116

```

117

118

**Usage Examples:**

119

120

```javascript

121

// Unfollow a blog by URL

122

await client.unfollowBlog({ url: 'some-blog.tumblr.com' });

123

console.log('Blog unfollowed successfully');

124

125

// Unfollow blogs from your following list

126

const following = await client.userFollowing({ limit: 10 });

127

for (const blog of following.blogs) {

128

if (blog.name.includes('spam')) {

129

await client.unfollowBlog({ url: blog.url });

130

console.log(`Unfollowed ${blog.name}`);

131

}

132

}

133

```

134

135

## Parameter Types

136

137

### Follow Blog Parameters

138

139

```javascript { .api }

140

type FollowBlogParams = { url: string } | { email: string };

141

142

interface FollowByUrl {

143

/** Blog URL to follow (can be short form or full URL) */

144

url: string;

145

}

146

147

interface FollowByEmail {

148

/** Email address associated with the blog */

149

email: string;

150

}

151

```

152

153

### Unfollow Blog Parameters

154

155

```javascript { .api }

156

interface UnfollowBlogParams {

157

/** Blog URL to unfollow */

158

url: string;

159

}

160

```

161

162

## Getting Required Information

163

164

### Obtaining Post ID and Reblog Key

165

166

```javascript

167

// Get post information from blog posts

168

const posts = await client.blogPosts('target-blog');

169

const targetPost = posts.posts[0];

170

171

console.log('Post ID:', targetPost.id);

172

console.log('Reblog Key:', targetPost.reblog_key);

173

174

// Now you can like/unlike the post

175

await client.likePost(targetPost.id, targetPost.reblog_key);

176

```

177

178

### Getting Post Information from Dashboard

179

180

```javascript

181

// Get posts from dashboard with like/reblog capabilities

182

const dashboard = await client.userDashboard({

183

reblog_info: true,

184

notes_info: true

185

});

186

187

dashboard.posts.forEach(async (post) => {

188

if (post.can_like && !post.liked) {

189

console.log(`Can like post ${post.id} by ${post.blog_name}`);

190

// await client.likePost(post.id, post.reblog_key);

191

}

192

});

193

```

194

195

### Finding Blogs to Follow

196

197

```javascript

198

// Discover blogs through tagged posts

199

const taggedPosts = await client.taggedPosts('photography');

200

const uniqueBlogs = [...new Set(taggedPosts.response.map(post => post.blog_name))];

201

202

console.log('Blogs posting about photography:');

203

uniqueBlogs.forEach(blogName => {

204

console.log(`- ${blogName}.tumblr.com`);

205

});

206

207

// Follow interesting blogs

208

for (const blogName of uniqueBlogs.slice(0, 5)) {

209

await client.followBlog({ url: `${blogName}.tumblr.com` });

210

}

211

```

212

213

## Bulk Operations

214

215

### Bulk Like Posts

216

217

```javascript

218

async function likeAllPostsFromBlog(blogName, maxPosts = 20) {

219

const posts = await client.blogPosts(blogName, { limit: maxPosts });

220

221

for (const post of posts.posts) {

222

try {

223

await client.likePost(post.id, post.reblog_key);

224

console.log(`Liked post ${post.id} from ${post.blog_name}`);

225

226

// Add delay to avoid rate limiting

227

await new Promise(resolve => setTimeout(resolve, 1000));

228

} catch (error) {

229

console.error(`Failed to like post ${post.id}:`, error.message);

230

}

231

}

232

}

233

```

234

235

### Clean Up Following List

236

237

```javascript

238

async function unfollowInactiveBlogs(daysSinceUpdate = 365) {

239

const cutoffTime = Date.now() / 1000 - (daysSinceUpdate * 24 * 60 * 60);

240

const following = await client.userFollowing();

241

242

for (const blog of following.blogs) {

243

if (blog.updated < cutoffTime) {

244

try {

245

await client.unfollowBlog({ url: blog.url });

246

console.log(`Unfollowed inactive blog: ${blog.name}`);

247

248

// Add delay to avoid rate limiting

249

await new Promise(resolve => setTimeout(resolve, 500));

250

} catch (error) {

251

console.error(`Failed to unfollow ${blog.name}:`, error.message);

252

}

253

}

254

}

255

}

256

```

257

258

### Like Posts from Dashboard

259

260

```javascript

261

async function likeInterestingDashboardPosts(keywords = []) {

262

const dashboard = await client.userDashboard({ limit: 20 });

263

264

for (const post of dashboard.posts) {

265

if (!post.liked && post.can_like) {

266

// Check if post contains interesting keywords

267

const postText = (post.title || '') + ' ' + (post.body || '') + ' ' + (post.tags || []).join(' ');

268

const hasKeyword = keywords.some(keyword =>

269

postText.toLowerCase().includes(keyword.toLowerCase())

270

);

271

272

if (hasKeyword) {

273

try {

274

await client.likePost(post.id, post.reblog_key);

275

console.log(`Liked post about "${keywords.find(k => postText.toLowerCase().includes(k.toLowerCase()))}"`);

276

} catch (error) {

277

console.error(`Failed to like post ${post.id}:`, error.message);

278

}

279

}

280

}

281

}

282

}

283

284

// Usage

285

await likeInterestingDashboardPosts(['photography', 'art', 'design']);

286

```

287

288

## Authentication Requirements

289

290

All social interaction methods require OAuth authentication:

291

292

```javascript

293

// Must have full OAuth credentials

294

const client = tumblr.createClient({

295

consumer_key: 'your-consumer-key',

296

consumer_secret: 'your-consumer-secret',

297

token: 'user-oauth-token',

298

token_secret: 'user-oauth-token-secret'

299

});

300

301

// These will fail without authentication

302

try {

303

await client.likePost('12345', 'abc123');

304

await client.followBlog({ url: 'some-blog.tumblr.com' });

305

} catch (error) {

306

if (error.message.includes('401')) {

307

console.error('OAuth authentication required');

308

}

309

}

310

```

311

312

## Rate Limiting and Best Practices

313

314

### Respect Rate Limits

315

316

```javascript

317

async function likePostsWithDelay(posts, delayMs = 1000) {

318

for (const post of posts) {

319

try {

320

await client.likePost(post.id, post.reblog_key);

321

console.log(`Liked post ${post.id}`);

322

323

// Wait between requests to avoid rate limiting

324

await new Promise(resolve => setTimeout(resolve, delayMs));

325

} catch (error) {

326

if (error.message.includes('429')) {

327

console.log('Rate limit hit, waiting 60 seconds...');

328

await new Promise(resolve => setTimeout(resolve, 60000));

329

// Retry the request

330

await client.likePost(post.id, post.reblog_key);

331

} else {

332

console.error(`Error liking post:`, error.message);

333

}

334

}

335

}

336

}

337

```

338

339

### Error Handling

340

341

```javascript

342

async function safelyFollowBlog(blogUrl) {

343

try {

344

await client.followBlog({ url: blogUrl });

345

return { success: true, message: `Followed ${blogUrl}` };

346

} catch (error) {

347

if (error.message.includes('403')) {

348

return { success: false, message: 'Blog does not allow follows or is private' };

349

} else if (error.message.includes('404')) {

350

return { success: false, message: 'Blog not found' };

351

} else if (error.message.includes('429')) {

352

return { success: false, message: 'Rate limit exceeded, try again later' };

353

} else {

354

return { success: false, message: `Unknown error: ${error.message}` };

355

}

356

}

357

}

358

359

// Usage

360

const result = await safelyFollowBlog('example-blog.tumblr.com');

361

console.log(result.message);

362

```

363

364

### Check Permissions Before Acting

365

366

```javascript

367

async function smartLikePosts(blogName) {

368

const posts = await client.blogPosts(blogName, {

369

reblog_info: true,

370

notes_info: true

371

});

372

373

for (const post of posts.posts) {

374

// Check if we can and should like this post

375

if (post.can_like && !post.liked) {

376

try {

377

await client.likePost(post.id, post.reblog_key);

378

console.log(`Liked ${post.type} post: ${post.summary || post.title || post.id}`);

379

} catch (error) {

380

console.error(`Cannot like post ${post.id}:`, error.message);

381

}

382

} else if (post.liked) {

383

console.log(`Already liked post ${post.id}`);

384

} else {

385

console.log(`Cannot like post ${post.id} (permissions)`);

386

}

387

}

388

}

389

```