Add SplatNet gear tweets

This commit is contained in:
Matt Isenhower 2017-09-20 14:27:28 -07:00
parent 3b586db65a
commit 83a56196f7
5 changed files with 167 additions and 20 deletions

View File

@ -25,4 +25,9 @@
padding: 0.5rem 0.75rem;
background: rgba($black-bis, 0.5);
}
.featured-merchandise {
transform: scale(2) rotate(-1.4deg);
min-width: 173px;
}
}

View File

@ -0,0 +1,63 @@
<template>
<Wrapper title="SplatNet Gear" :time="$route.params.startTime" v-if="merchandises">
<div class="columns">
<div class="column is-5">
<h1 class="title is-3 font-splatoon2 has-text-centered">New Gear</h1>
</div>
<div class="column" style="display: flex; align-items: center; justify-content: center;">
<h1 class="title is-4 font-splatoon2 has-text-centered">Still Available</h1>
</div>
</div>
<div class="columns">
<div class="column is-5" style="display: flex; align-items: center; justify-content: center;">
<MerchandiseBox
:merchandise="featuredMerchandise"
:now="$route.params.startTime"
class="featured-merchandise"
></MerchandiseBox>
</div>
<div class="column">
<div class="columns is-multiline is-centered">
<div class="column is-one-third" v-for="(merchandise, index) in otherMerchandises">
<MerchandiseBox
:merchandise="merchandise"
:now="$route.params.startTime"
:class="(index % 2 == 0) ? 'tilt-right' : 'tilt-left'"
></MerchandiseBox>
</div>
</div>
</div>
</div>
</Wrapper>
</template>
<script>
import axios from 'axios';
import Wrapper from '@/js/components/screenshots/Wrapper.vue';
import MerchandiseBox from '@/js/components/splatoon/MerchandiseBox.vue';
export default {
components: { Wrapper, MerchandiseBox },
data() {
return {
merchandises: null,
};
},
computed: {
featuredMerchandise() {
if (this.merchandises)
return this.merchandises.find(m => m.end_time == this.$route.params.endTime);
},
otherMerchandises() {
if (this.merchandises)
return this.merchandises.filter(m => m != this.featuredMerchandise && m.end_time > this.$route.params.startTime);
},
},
created() {
axios.get('data/merchandises.json')
.then(response => this.merchandises = response.data.merchandises)
},
}
</script>

View File

@ -8,8 +8,10 @@ import VueRouter from 'vue-router';
Vue.use(VueRouter);
import Schedules from './components/screenshots/schedules/Schedules.vue';
import SplatNetGear from './components/screenshots/splatnetgear/SplatNetGear.vue';
const routes = [
{ path: '/schedules/:startTime', component: Schedules },
{ path: '/splatNetGear/:startTime/:endTime', component: SplatNetGear },
];
const router = new VueRouter({ routes });

View File

@ -22,7 +22,8 @@ async function captureScreenshot(options) {
// Create a new page and set the viewport
const page = await browser.newPage();
page.setViewport(viewport);
let thisViewport = Object.assign({}, viewport, options.viewport);
page.setViewport(thisViewport);
// Navigate to the URL
await page.goto(options.url, {
@ -46,6 +47,14 @@ function captureScheduleScreenshot(startTime) {
return captureScreenshot({ url });
}
function captureGearScreenshot(startTime, endTime) {
let url = new URL(htmlUrl);
url.hash = `/splatNetGear/${startTime}/${endTime}`;
return captureScreenshot({ url, viewport: { height: 660 } });
}
module.exports = {
captureScheduleScreenshot,
captureGearScreenshot,
}

View File

@ -52,6 +52,28 @@ function updateLastTweetTime(key, time) {
fs.writeFileSync(lastTweetTimesPath, JSON.stringify(lastTweetTimes));
}
function postMediaTweet(imageData, statusText) {
return new Promise((resolve, reject) => {
// Upload the image
client.post('media/upload', { media: imageData }, (error, media, response) => {
if (error)
return reject(error);
let status = {
status: statusText,
media_ids: media.media_id_string,
};
client.post('statuses/update', status, (error, tweet, response) => {
if (error)
return reject(error);
resolve(tweet);
});
});
});
}
/**
* Twitter posts
*/
@ -63,6 +85,7 @@ async function maybePostTweets() {
}
await maybePostScheduleTweet();
await maybePostGearTweet();
}
/**
@ -103,33 +126,78 @@ async function maybePostScheduleTweet() {
updateLastTweetTime(key, time);
}
function postScheduleTweet(startTime) {
return new Promise(async (resolve, reject) => {
// Generate the image
let imageData = await screenshots.captureScheduleScreenshot(startTime);
async function postScheduleTweet(startTime) {
// Generate the image
let imageData = await screenshots.captureScheduleScreenshot(startTime);
// Upload the image
client.post('media/upload', { media: imageData }, (error, media, response) => {
if (error)
return reject(error);
// Post the tweet
return await postMediaTweet(imageData, 'Current Splatoon 2 map rotation, via https://splatoon2.ink #splatoon2');
}
let status = {
status: 'Current Splatoon 2 map rotation, via https://splatoon2.ink #splatoon2',
media_ids: media.media_id_string,
};
/**
* Gear tweets
*/
client.post('statuses/update', status, (error, tweet, response) => {
if (error)
return reject(error);
function getMerchandises() {
let merchandisesPath = `${dataPath}/merchandises.json`;
if (!fs.existsSync(merchandisesPath)) {
console.warn('Twitter: Gear: merchandises.json does not exist');
return [];
}
return JSON.parse(fs.readFileSync(merchandisesPath)).merchandises;
}
resolve(tweet);
});
});
});
async function maybePostGearTweet() {
const key = 'gear';
// What time are we posting the schedule for?
let time = getTopOfCurrentHour();
// Make sure we have merchandises
let merchandises = getMerchandises();
if (!merchandises.length) {
console.info('Twitter: Gear: No merchandises');
return;
}
// This one is a little different: we only have end_times for merchandise items, so we
// need to track the latest end_time we've posted
let endTimes = merchandises.map(m => m.end_time);
let lastEndTime = Math.max(...endTimes);
// Have we already posted for this time?
if (!shouldTweet(key, lastEndTime)) {
console.info('Twitter: Gear: Already posted for this hour', lastEndTime);
return;
}
// Everything looks good, let's post a tweet
await postGearTweet(time, lastEndTime);
console.info('Twitter: Gear: Posted latest SplatNet gear');
// Update the last tweet time
updateLastTweetTime(key, lastEndTime);
}
async function postGearTweet(startTime, endTime) {
// Generate the image
let imageData = await screenshots.captureGearScreenshot(startTime, endTime);
// Generate the text
let gearText;
let merchandise = getMerchandises().find(g => g.end_time == endTime);
if (!merchandise)
return;
gearText = `Up now on SplatNet: ${merchandise.gear.name} with ${merchandise.skill.name}, via https://splatoon2.ink #splatoon2 #splatnet2`;
// Post the tweet
return await postMediaTweet(imageData, gearText);
}
module.exports = {
maybePostTweets,
postScheduleTweet,
postGearTweet,
}
require('make-runnable/custom')({ printOutputFrame: false });