Make it a web app
This commit is contained in:
parent
115c237d44
commit
ab4990735e
10
README.md
10
README.md
@ -7,18 +7,10 @@ localizations.
|
|||||||
Relies on data from [Justwatch.com](https://www.justwatch.com/).
|
Relies on data from [Justwatch.com](https://www.justwatch.com/).
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
Just serve `index.html` with a webserver with [CORS headers enabled](https://developer.mozilla.org/fr/docs/Web/HTTP/CORS).
|
||||||
python3 main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
146
index.html
Normal file
146
index.html
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Multiwatch</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
|
||||||
|
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-bullet {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<h1><a href="./">Multiwatch</a></h1>
|
||||||
|
<p v-if="step > 1"><a href="./">Back</a></p>
|
||||||
|
|
||||||
|
<p v-if="error" class="error">{{ error }}</p>
|
||||||
|
|
||||||
|
<div v-if="step == 1">
|
||||||
|
<h2>Search</h2>
|
||||||
|
|
||||||
|
<form id="searchForm" v-on:submit.prevent="search">
|
||||||
|
<p>
|
||||||
|
<label for="title">Title:</label>
|
||||||
|
<input type="text" v-model="title" id="title" />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Search"/>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<ul v-if="step == 2" class="no-bullet">
|
||||||
|
<li v-for="(item, index) in searchItems">
|
||||||
|
<img class="pointer" v-bind:src="item.poster_url" v-bind:alt="item.title" v-on:click="() => loadItem(index)" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div v-else>
|
||||||
|
<div v-for="(localeOffers, locale) in offers">
|
||||||
|
<h3>{{ availableLocales[locale] }}</h3>
|
||||||
|
<ul v-if="localeOffers.length > 0" class="left">
|
||||||
|
<li v-for="offer in localeOffers"><a v-bind:href="offer">{{ offer }}</a></li>
|
||||||
|
</ul>
|
||||||
|
<p v-else>None</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
data: {
|
||||||
|
availableLocales: {
|
||||||
|
'fr_FR': 'France',
|
||||||
|
'en_AU': 'Australia',
|
||||||
|
'en_CA': 'Canada',
|
||||||
|
'de_DE': 'Germany',
|
||||||
|
'pl_PL': 'Poland',
|
||||||
|
'en_SG': 'Singapore',
|
||||||
|
'en_UK': 'United Kingdom',
|
||||||
|
},
|
||||||
|
error: null,
|
||||||
|
title: '',
|
||||||
|
searchItems: [],
|
||||||
|
offers: {},
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
search() {
|
||||||
|
fetch(`https://apis.justwatch.com/content/titles/fr_FR/popular?language=fr&body={"page_size":5,"page":1,"query":"${this.title}","content_types":["show","movie"]}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
this.error = null;
|
||||||
|
if (!response.items || response.items.length == 0) {
|
||||||
|
this.error = 'Not found'
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchItems = response.items.map((item) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.title,
|
||||||
|
type: item.object_type,
|
||||||
|
poster_url: `https://images.justwatch.com${item['poster'].replace('{profile}', 's276')}`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.step += 1;
|
||||||
|
})
|
||||||
|
.catch(exc => this.error = exc);
|
||||||
|
},
|
||||||
|
loadItem(index) {
|
||||||
|
this.offers = {};
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
|
var promises = [];
|
||||||
|
Object.keys(this.availableLocales).forEach((locale) => {
|
||||||
|
var searchItem = this.searchItems[index];
|
||||||
|
var url = `https://apis.justwatch.com/content/titles/${searchItem.type}/${searchItem.id}/locale/${locale}?language=fr`
|
||||||
|
promises.push(fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
if (!response.offers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.offers[locale] = response.offers
|
||||||
|
.filter(item => item.monetization_type == 'flatrate')
|
||||||
|
.map(item => item.urls.standard_web);
|
||||||
|
this.offers[locale] = [...new Set(this.offers[locale])];
|
||||||
|
})
|
||||||
|
.catch(exc => this.error = exc)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
Promise.all(promises).then(() => this.step += 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
81
main.py
81
main.py
@ -1,81 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.WARNING)
|
|
||||||
|
|
||||||
LOCALES = {
|
|
||||||
'fr_FR': 'France',
|
|
||||||
'en_AU': 'Australia',
|
|
||||||
'en_CA': 'Canada',
|
|
||||||
'de_DE': 'Germany',
|
|
||||||
'pl_PL': 'Poland',
|
|
||||||
'en_SG': 'Singapore',
|
|
||||||
'en_UK': 'United Kingdom',
|
|
||||||
}
|
|
||||||
|
|
||||||
query = input('Movie/Show title? ')
|
|
||||||
|
|
||||||
req = requests.get(
|
|
||||||
'https://apis.justwatch.com/content/titles/fr_FR/popular',
|
|
||||||
params={
|
|
||||||
'language': 'fr',
|
|
||||||
'body': '{"page_size":5,"page":1,"query":"%s","content_types":["show","movie"]}' % query
|
|
||||||
}
|
|
||||||
)
|
|
||||||
logging.info(req.url)
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
list = []
|
|
||||||
|
|
||||||
if not 'items' in req.json() or not req.json()['items']:
|
|
||||||
print('NOT FOUND')
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
for item in req.json()['items']:
|
|
||||||
list.append((item['object_type'], item['id']))
|
|
||||||
print('%s. %s - %s' % (
|
|
||||||
i, item['title'],
|
|
||||||
'https://images.justwatch.com%s' % (
|
|
||||||
item['poster'].replace(r'{profile}', 's276')
|
|
||||||
)
|
|
||||||
))
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
print()
|
|
||||||
title_nb = None
|
|
||||||
while title_nb not in range(len(list)):
|
|
||||||
title_nb = input('Choice? ')
|
|
||||||
try:
|
|
||||||
title_nb = int(title_nb)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
print()
|
|
||||||
|
|
||||||
print('Available from these flatrate services:')
|
|
||||||
for locale, locale_name in LOCALES.items():
|
|
||||||
print('> %s:' % locale_name)
|
|
||||||
url = (
|
|
||||||
'https://apis.justwatch.com/content/titles/%s/%s/locale/%s?language=fr'
|
|
||||||
% (list[title_nb][0], list[title_nb][1], locale)
|
|
||||||
)
|
|
||||||
logging.info(url)
|
|
||||||
req = requests.get(url)
|
|
||||||
offers = {}
|
|
||||||
if not req.json().get('offers', []):
|
|
||||||
print(' None')
|
|
||||||
print()
|
|
||||||
continue
|
|
||||||
|
|
||||||
for offer in req.json().get('offers', []):
|
|
||||||
if offer['monetization_type'] != 'flatrate':
|
|
||||||
continue
|
|
||||||
offers[offer['urls']['standard_web']] = {}
|
|
||||||
|
|
||||||
for url, offer in offers.items():
|
|
||||||
print(' * %s' % url)
|
|
||||||
print()
|
|
@ -1 +0,0 @@
|
|||||||
requests
|
|
Loading…
Reference in New Issue
Block a user