Compare commits

..
14 changed files with 1641 additions and 1018 deletions

View file

@ -1,28 +0,0 @@
name: website
on: push
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cache
uses: actions/cache@v3
with:
path: cache/
key: cache
- name: Generate website
run: pip3 install beautifulsoup4 && python3 scraper.py
- name: Create cname file
run: echo 'moustache-et-cinema.fr' > docs/CNAME
- name: Deploy to GitHub Pages
if: success()
uses: crazy-max/ghaction-github-pages@v2
with:
target_branch: gh-pages
build_dir: docs
jekyll: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View file

@ -1,3 +0,0 @@
cache/
docs/
.DS_Store

0
.nojekyll Normal file
View file

1
CNAME Normal file
View file

@ -0,0 +1 @@
moustache-et-cinema.fr

21
LICENSE
View file

@ -1,21 +0,0 @@
ANTI-CAPITALIST SOFTWARE LICENSE (v 1.4)
Copyright © 2022 Stéphane Boulay
This is anti-capitalist software, released for free use by individuals and organizations that do not operate by capitalist principles.
Permission is hereby granted, free of charge, to any person or organization (the "User") obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, merge, distribute, and/or sell copies of the Software, subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in all copies or modified versions of the Software.
2. The User is one of the following:
a. An individual person, laboring for themselves
b. A non-profit organization
c. An educational institution
d. An organization that seeks shared profit for all of its members, and allows non-members to set the cost of their labor
3. If the User is an organization with owners, then all owners are workers and all workers are owners with equal equity and/or equal vote.
4. If the User is an organization, then the User is not law enforcement or military, or working for or under either.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,15 +0,0 @@
![Moustache et cinéma](/images/avatar.png)
# Moustache et cinema
Un petit site de recos cinéma avec des fichiers texte en quelques dizaines de lignes de code.
Des fois il casse.
## Contribution
### Génération
```bash
pip install -r requirements.txt
python scraper.py
```

1640
index.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
tt14039582
tt10280296
tt4068576
tt8165192
tt5867314
tt11655202
tt7294150
tt9731534
tt0093845
tt0185188
tt7888964
tt0860906
tt6878882
tt7014378
tt7737528
tt10293406
tt2458948

View file

@ -1,39 +0,0 @@
tt6931658
tt10283270
tt14465706
tt1016150
tt9541602
tt13145534
tt14253846
tt6710474
tt10954984
tt14500584
tt9098872
tt10324144
tt12593682
tt0096414
tt14810692
tt16529222
tt11866324
tt0090956
tt6869538
tt7740496
tt1535492
tt0118956
tt4849438
tt2631186
tt13841850
tt13446168
tt9916362
tt0077588
tt1745960
tt7468056
tt8178634
tt11138512
tt2330912
tt0088194
tt0074586
tt0063056
tt7270808
tt11790780
tt14199590

View file

@ -1,104 +0,0 @@
tt13086266
tt2891070
tt23289160
tt28236368
tt1615147
tt26915336
tt0070030
tt16300962
tt23049206
tt20452218
tt19820538
tt0103162
tt1535491
tt0105382
tt1136617
tt28106766
tt19319352
tt28254460
tt6587046
tt9900782
tt18313356
tt5537002
tt0057565
tt0077175
tt20465746
tt0076299
tt26350277
tt21440780
tt2025526
tt14509110
tt0819765
tt1202514
tt0076725
tt17009710
tt0068744
tt0279112
tt0059729
tt0051036
tt10095582
tt0104352
tt15242330
tt15398776
tt4768764
tt9015178
tt14379088
tt14032696
tt0059346
tt0067148
tt10059518
tt0330536
tt0310775
tt0073234
tt0052571
tt4576612
tt12263384
tt9362722
tt0901487
tt0796212
tt9340892
tt15152316
tt14994254
tt10275534
tt0113194
tt0043338
tt1740002
tt2906216
tt27197387
tt22695402
tt0074806
tt0044954
tt6138228
tt12672536
tt21243618
tt16428256
tt14846026
tt0491399
tt13729232
tt0072926
tt9412268
tt16900880
tt0065916
tt6788942
tt0042229
tt15568526
tt4771896
tt0089714
tt3915174
tt0084899
tt0091556
tt13274576
tt0269743
tt0097244
tt14208870
tt9844938
tt0087799
tt0077294
tt3037164
tt1124052
tt12788488
tt8093700
tt15474916
tt15791034
tt11564570
tt0094374

View file

@ -1,3 +0,0 @@
</main>
</body>
</html>

View file

@ -1,654 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Moustache et cinéma - Les recommandations cinéma de GKPluginBaby</title>
<meta name="description" content="Les recommandations cinéma de Vnr Herzog." />
<meta property="og:title" content="Moustache et cinéma - Les recommandations cinéma de Vnr Herzog" />
<meta property="og:description" content="Les recommandations cinéma de Vnr Herzog." />
<meta property="og:image" content="https://moustache-et-cinema.fr/images/og.png" />
<meta property="og:image:alt" content="Les recommandations cinéma de Vnr Herzog." />
<meta property="og:locale" content="fr_FR" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:url" content="https://moustache-et-cinema.fr" />
<link rel="canonical" href="https://moustache-et-cinema.fr" />
<link rel="icon" href="/images/favicon.ico" />
<link rel="apple-touch-icon" href="/images/apple-icon.png">
<meta name="theme-color" content="#000000" />
<style>
:root {
--active-brightness: 0.85;
--border-radius: 5px;
--box-shadow: 2px 2px 10px;
--color: #118bee;
--color-accent: #118bee15;
--color-bg: #fff;
--color-bg-secondary: #e9e9e9;
--color-link: #118bee;
--color-secondary: #920de9;
--color-secondary-accent: #920de90b;
--color-shadow: #f4f4f4;
--color-table: #118bee;
--color-text: #000;
--color-text-secondary: #999;
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
--hover-brightness: 1.2;
--justify-important: center;
--justify-normal: left;
--line-height: 1.5;
--width-card: 285px;
--width-card-medium: 460px;
--width-card-wide: 800px;
--width-content: 1080px
}
@media (prefers-color-scheme: dark) {
:root {
--color: #0097fc;
--color-accent: #0097fc4f;
--color-bg: #333;
--color-bg-secondary: #555;
--color-link: #0097fc;
--color-secondary: #e20de9;
--color-secondary-accent: #e20de94f;
--color-shadow: #bbbbbb20;
--color-table: #0097fc;
--color-text: #f7f7f7;
--color-text-secondary: #aaa
}
}
article aside {
background: var(--color-secondary-accent);
border-left: 4px solid var(--color-secondary);
padding: 0.01rem 0.8rem
}
body {
background: var(--color-bg);
color: var(--color-text);
font-family: var(--font-family);
line-height: var(--line-height);
margin: 0;
overflow-x: hidden;
padding: 0
}
footer,
header,
main {
margin: 0 auto;
max-width: var(--width-content);
padding: 3rem 1rem
}
hr {
background-color: var(--color-bg-secondary);
border: none;
height: 1px;
margin: 4rem 0;
width: 100%
}
section {
display: flex;
flex-wrap: wrap;
justify-content: var(--justify-important)
}
article img,
section img {
max-width: 100%
}
section pre {
overflow: auto
}
section aside {
border: 1px solid var(--color-bg-secondary);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow) var(--color-shadow);
margin: 1rem;
padding: 1.25rem;
width: var(--width-card)
}
section aside:hover {
box-shadow: var(--box-shadow) var(--color-bg-secondary)
}
[hidden] {
display: none
}
article header,
div header,
main header {
padding-top: 0
}
header {
text-align: var(--justify-important)
}
header a b,
header a em,
header a i,
header a strong {
margin-left: 0.5rem;
margin-right: 0.5rem
}
header nav img {
margin: 1rem 0
}
section header {
padding-top: 0;
width: 100%
}
nav {
align-items: center;
display: flex;
font-weight: bold;
justify-content: space-between;
margin-bottom: 7rem
}
nav ul {
list-style: none;
padding: 0
}
nav ul li {
display: inline-block;
margin: 0 0.5rem;
position: relative;
text-align: left
}
nav ul li:hover ul {
display: block
}
nav ul li ul {
background: var(--color-bg);
border: 1px solid var(--color-bg-secondary);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow) var(--color-shadow);
display: none;
height: auto;
left: -2px;
padding: 0.5rem 1rem;
position: absolute;
top: 1.7rem;
white-space: nowrap;
width: auto;
z-index: 1
}
nav ul li ul::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: -0.5rem;
height: 0.5rem
}
nav ul li ul li,
nav ul li ul li a {
display: block
}
code,
samp {
background-color: var(--color-accent);
border-radius: var(--border-radius);
color: var(--color-text);
display: inline-block;
margin: 0 0.1rem;
padding: 0 0.5rem
}
details {
margin: 1.3rem 0
}
details summary {
font-weight: bold;
cursor: pointer
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: var(--line-height)
}
mark {
padding: 0.1rem
}
ol li,
ul li {
padding: 0.2rem 0
}
p {
margin: 0.75rem 0;
padding: 0;
width: 100%
}
pre {
margin: 1rem 0;
max-width: var(--width-card-wide);
padding: 1rem 0
}
pre code,
pre samp {
display: block;
max-width: var(--width-card-wide);
padding: 0.5rem 2rem;
white-space: pre-wrap
}
small {
color: var(--color-text-secondary)
}
sup {
background-color: var(--color-secondary);
border-radius: var(--border-radius);
color: var(--color-bg);
font-size: xx-small;
font-weight: bold;
margin: 0.2rem;
padding: 0.2rem 0.3rem;
position: relative;
top: -2px
}
a {
color: var(--color-link);
display: inline-block;
font-weight: bold;
text-decoration: none
}
a:active {
filter: brightness(var(--active-brightness));
text-decoration: underline
}
a:hover {
filter: brightness(var(--hover-brightness));
text-decoration: underline
}
a b,
a em,
a i,
a strong,
button {
border-radius: var(--border-radius);
display: inline-block;
font-size: medium;
font-weight: bold;
line-height: var(--line-height);
margin: 0.5rem 0;
padding: 1rem 2rem
}
button {
font-family: var(--font-family)
}
button:active {
filter: brightness(var(--active-brightness))
}
button:hover {
cursor: pointer;
filter: brightness(var(--hover-brightness))
}
a b,
a strong,
button {
background-color: var(--color-link);
border: 2px solid var(--color-link);
color: var(--color-bg)
}
a em,
a i {
border: 2px solid var(--color-link);
border-radius: var(--border-radius);
color: var(--color-link);
display: inline-block;
padding: 1rem 2rem
}
article aside a {
color: var(--color-secondary)
}
figure {
margin: 0;
padding: 0
}
figure img {
max-width: 100%
}
figure figcaption {
color: var(--color-text-secondary)
}
button:disabled,
input:disabled {
background: var(--color-bg-secondary);
border-color: var(--color-bg-secondary);
color: var(--color-text-secondary);
cursor: not-allowed
}
button[disabled]:hover {
filter: none
}
form {
border: 1px solid var(--color-bg-secondary);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow) var(--color-shadow);
display: block;
max-width: var(--width-card-wide);
min-width: var(--width-card);
padding: 1.5rem;
text-align: var(--justify-normal)
}
form header {
margin: 1.5rem 0;
padding: 1.5rem 0
}
input,
label,
select,
textarea {
display: block;
font-size: inherit;
max-width: var(--width-card-wide)
}
input[type="checkbox"],
input[type="radio"] {
display: inline-block
}
input[type="checkbox"]+label,
input[type="radio"]+label {
display: inline-block;
font-weight: normal;
position: relative;
top: 1px
}
input,
select,
textarea {
border: 1px solid var(--color-bg-secondary);
border-radius: var(--border-radius);
margin-bottom: 1rem;
padding: 0.4rem 0.8rem
}
input[readonly],
textarea[readonly] {
background-color: var(--color-bg-secondary)
}
label {
font-weight: bold;
margin-bottom: 0.2rem
}
table {
border: 1px solid var(--color-bg-secondary);
border-radius: var(--border-radius);
border-spacing: 0;
display: inline-block;
max-width: 100%;
overflow-x: auto;
padding: 0;
white-space: nowrap
}
table td,
table th,
table tr {
padding: 0.4rem 0.8rem;
text-align: var(--justify-important)
}
table thead {
background-color: var(--color-table);
border-collapse: collapse;
border-radius: var(--border-radius);
color: var(--color-bg);
margin: 0;
padding: 0
}
table thead th:first-child {
border-top-left-radius: var(--border-radius)
}
table thead th:last-child {
border-top-right-radius: var(--border-radius)
}
table thead th:first-child,
table tr td:first-child {
text-align: var(--justify-normal)
}
table tr:nth-child(even) {
background-color: var(--color-accent)
}
blockquote {
display: block;
font-size: x-large;
line-height: var(--line-height);
margin: 1rem auto;
max-width: var(--width-card-medium);
padding: 1.5rem 1rem;
text-align: var(--justify-important)
}
blockquote footer {
color: var(--color-text-secondary);
display: block;
font-size: small;
line-height: var(--line-height);
padding: 1.5rem 0
}
:root {
--step--2: clamp(0.63rem, calc(0.82rem + -0.28vw), 0.77rem);
--step--1: clamp(0.82rem, calc(0.80rem + 0.12vw), 0.88rem);
--step-0: clamp(0.88rem, calc(0.73rem + 0.73vw), 1.25rem);
--step-1: clamp(0.93rem, calc(0.61rem + 1.63vw), 1.77rem);
--step-2: clamp(1.00rem, calc(0.41rem + 2.93vw), 2.50rem);
--step-3: clamp(1.06rem, calc(0.10rem + 4.82vw), 3.53rem);
--step-4: clamp(1.13rem, calc(-0.37rem + 7.54vw), 5.00rem);
--step-5: clamp(1.21rem, calc(-1.08rem + 11.43vw), 7.07rem);
}
h1 {
font-size: var(--step-3);
text-transform: uppercase;
}
h2 {
font-size: var(--step-2);
}
h3 {
font-size: var(--step-1);
}
h4 {
font-size: var(--step-0);
}
body {
font-size: var(--step--1);
color: var(--color-text);
font-family: monospace;
}
header {
max-width: 1440px;
margin: auto;
text-align: center;
}
section {
display: grid;
grid-template-columns: 1fr 11fr;
gap: 1rem;
}
.movies {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-template-rows: 1fr auto auto auto;
gap: 1rem;
}
article {
border: 4px solid var(--color-text);
display: grid;
padding: 1rem;
grid-row: auto / span 4;
grid-template-rows: subgrid;
}
article h3 {
margin: 0;
line-height: 1;
text-transform: uppercase;
}
article img {
height: 100%;
object-fit: contain;
width: 100%;
aspect-ratio: 2/3;
max-height: 400px;
}
main {
max-width: unset;
margin: auto;
}
nav {
justify-content: center;
margin-bottom: 0;
}
a {
color: var(--color-text);
text-decoration: underline;
}
.flow>*+* {
margin-top: 1rem;
}
.flow-big>*+* {
margin-top: 5rem;
}
.moustache {
width: calc(8ch - 8px);
border-radius: 50%;
border: 4px solid var(--color-text);
filter: grayscale(100%) contrast(1.5);
}
.avatar {
filter: grayscale(1) contrast(2);
}
.stick {
position: sticky;
top: 1rem;
text-align: center;
}
@media (max-width: 790px) {
section {
grid-template-columns: 1fr;
}
article {
max-width: unset;
grid-template-columns: 1fr;
}
article img {
max-height: 500px;
}
}
.gold,
.gold a {
background: #ffcc33;
color: black;
border: 4px solid #ffcc33;
}
.silver,
.silver a {
background: silver;
color: black;
border: 4px solid silver;
}
.bronze,
.bronze a {
background: #cd7f32;
border: 4px solid #cd7f32;
color: black;
}
</style>
</head>
<body>
<header>
<img class="avatar" src="images/avatar.png" alt="Avatar de Vnr Herzog">
<h1>Moustache et cinéma</h1>
<p>Les recommandations ciné de <a href="https://twitter.com/VnrHerzog">Vnr Herzog.</a></p>
<nav>
MENU
</nav>
</header>
<main class="flow-big">

View file

@ -1,2 +0,0 @@
requests==2.31.0
beautifulsoup4==4.12.2

View file

@ -1,132 +0,0 @@
import os
import json
import re
import requests
import shutil
from bs4 import BeautifulSoup
import string
# Config
path = "movies"
cache_path = "cache"
url = "https://www.imdb.com/title/"
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36', 'Accept-Language': 'fr'}
# Years
years = []
files = os.listdir(path)
files_sorted = sorted(files)
files_sorted.reverse()
for file in files_sorted:
years.append(file.replace(".txt", ""))
# Movies
all_movies = []
menu = "<ul>"
for year in years:
print("\n" + year)
file = open(path + "/" + year + ".txt", "r")
movies_ids = file.read().split("\n")
menu += "<li><a href=\"#" + year + "\">" + year + "</a></li>"
movies = []
for movie_infos in movies_ids:
if movie_infos == "":
continue
movie_arr = re.split(" ", movie_infos)
movie_id = movie_arr[0]
if len(movie_arr) >= 2:
podium = movie_arr[1]
else:
podium = ""
if os.path.exists("cache/" + movie_id + ".json"):
cache_file = open("cache/" + movie_id + ".json", "r")
cache_content = cache_file.read()
cache_array = json.loads(cache_content)
cache_file.close()
print("Cached:", cache_array["title"])
movies.append(cache_array)
else:
link = url + movie_id
res = requests.get(link, headers=headers)
soup = BeautifulSoup(res.content, "html.parser")
title = soup.find("h1").get_text()
print("Fetch:", str(title))
image = soup.find("meta", property="og:image")
plot = soup.find("meta", property="twitter:image:alt")
movie = {
"id": movie_id,
"title": str(title),
"image": image.get("content"),
"plot": plot.get("content"),
"link": link,
"year": year,
"podium": podium,
}
movies.append(movie)
cache_json = json.dumps(movie)
if not os.path.exists("cache"):
os.makedirs("cache")
cache_file = open("cache/" + movie_id + ".json", "w")
cache_file.write(cache_json)
cache_file.close()
year_arr = {"year": str(year), "movies": movies}
all_movies.append(year_arr)
# Building HTML
print("\nBuilding HTML page")
menu += "</ul>"
content = ""
for item in all_movies:
print(item["year"])
content += (
"\n <section>\n <div>\n <div class=\"stick\"><img class=\"moustache\" src=\"images/"
+ item["year"]
+ ".png\" aria-hidden=\"true\" /><h2 id="
+ item["year"]
+ ">"
+ item["year"]
+ "</h2></div>\n </div>\n <div class=\"movies\">\n"
)
for movie in item["movies"]:
movie_string = (
" <article class=\"flow "
+ movie["podium"]
+ "\" id=\""
+ movie["id"]
+ "\">\n <img loading=\"lazy\" src=\""
+ movie["image"]
+ "\" alt=\""
+ movie["title"]
+ "\" />\n <h3>"
+ movie["title"]
+ "</h3>\n <p>"
+ movie["plot"]
+ "</p>\n <a href=\""
+ movie["link"]
+ "\">IMDB</a>\n </article>\n"
)
content += movie_string
content += " </div>\n </section>\n"
start = open("partials/start.html", "r", encoding="utf-8")
start_width_menu = start.read().replace("MENU", menu)
end = open("partials/end.html", "r", encoding="utf-8")
complete = start_width_menu + content + end.read()
# Create output
if os.path.exists("docs"):
shutil.rmtree("docs")
os.makedirs("docs")
f = open("docs/index.html", "w", encoding="utf-8")
f.write(complete)
f.close()
# Copy assets
assets = os.listdir("images")
os.makedirs("docs/images")
if assets:
for asset in assets:
asset = os.path.join("images/", asset)
if os.path.isfile(asset):
shutil.copy(asset, "docs/images/")
else:
print("No assets found!")