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

Added Genius support with some small bug fixes and such #76

Merged
merged 6 commits into from
Feb 19, 2023
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
47 changes: 35 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,28 @@

<h2 align="center">Status</h2>

<h4 align="center">
🚧 MetaTube 🚀 Under construction... 🚧 <br/>
<h4 align="center">
:heavy_check_mark: MetaTube 🚀 Finished! :heavy_check_mark: <br/>
</h4>

<hr>

<p align="center">
<a href="#dart-about">About</a> &#xa0; | &#xa0;
<a href="#dart-about">About</a> &#xa0; | &#xa0;
<a href="#sparkles-features">Features</a> &#xa0; | &#xa0;
<a href="#rocket-technologies">Technologies</a> &#xa0; | &#xa0;
<a href="#white_check_mark-requirements">Requirements</a> &#xa0; | &#xa0;
<a href="#checkered_flag-starting">Starting</a> &#xa0; | &#xa0;
<a href="#memo-license">License</a> &#xa0; | &#xa0;
<a href="#disclaimer">Disclaimer</a> &#xa0; | &#xa0;
<a href="#disclaimer">Disclaimer</a> &#xa0; | &#xa0;
<a href="https://github.com/JVT038" target="_blank">Author</a>
</p>

<br>

## :dart: About ##

MetaTube downloads video from YouTube and can add metadata from a specified metadata provider on the downloaded file.
MetaTube downloads video from YouTube and can add metadata from a specified metadata provider on the downloaded file.
Normal view | Dark mode|
--- | ---
![startpage](https://user-images.githubusercontent.com/47184046/147980156-e3ee71e4-a4cd-4fee-808b-c4b3c9530e9f.png) | ![darkstartpage](https://user-images.githubusercontent.com/47184046/147980017-bd3bc8bf-2589-4ee5-8d9c-1785ba906982.png)
Expand Down Expand Up @@ -96,8 +96,11 @@ For a complete list, visit the [Dependencies overview](https://github.com/JVT038
Before starting :checkered_flag:, you need to have [Git](https://git-scm.com) and [Python 3.8 or higher](https://python.org/downloads) installed.

## :checkered_flag: Starting ##

### :whale: Using Docker ###

CLI docker:

```docker
docker run \
-d \
Expand All @@ -110,7 +113,9 @@ docker run \
-v /metatube:/database:rw \
jvt038/metatube:latest
```

Docker-compose:

```
version: '3.3'
services:
Expand All @@ -127,8 +132,11 @@ services:
- '/downloads:/downloads:rw'
- '/metatube:/database:rw'
```

You need to set the variable `DATABASE_URL` to a custom mount point (in these examples `/database`), because otherwise your database file will reset everytime the Docker container updates.

### :hammer_and_wrench: Manually build and start server ###

```bash
# Clone this project
$ git clone https://github.com/JVT038/metatube
Expand Down Expand Up @@ -166,6 +174,7 @@ $ python metatube.py

# The server will initialize in the <http://localhost:5000>
```

You can set the following environment variables:
Name | Description | Default value
---|---|---
Expand All @@ -179,33 +188,45 @@ LOG | Whether to keep logs or not | False
SOCKET_LOG | Whether to log in- and outcoming websocket connections; warning: your console can be spammed with connections | False
LOG_LEVEL | Numeric value from which MetaTube will keep logs. Info [here](https://docs.python.org/3/howto/logging.html#logging-levels) | 10
URL_SUBPATH | Set the URL subpath, if you want to run MetaTube on a subpath. Example: `/metatube` will run the server on `host:port/metatube` | /

```bash
# On Windows 10, you can set an environment variable like this:
$ set ENVIRONMENT_VARIABLE = Value

# On Linux and MacOS, you can set an environment variable like this:
$ export ENVIRONMENT_VARIABLE = Value
```

Additionally you can create a file called `.flaskenv` and set the environment variables in there.
An example is provided in [example.flaskenv](example.flaskenv). You can use that template and rename the file to `.flaskenv`.

## Fix the artist values

So I recently discovered I made a mistake in the process of adding artists to files. <br/>
Some songs have tags multiple artists, and I noticed these tags were misinterpreted by my audio player. <br/>
Basically, the `TPE1` tag contained was like this: `['artist 1; artist 2']`, while it should've been `['artist 1', 'artist 2']`. <br/>
Thanks to [#310](https://github.com/quodlibet/mutagen/issues/310) I discovered this, corrected it in `metadata.py` and wrote a small script in [fixartists.py](fixartists.py) to fix the existing audio files that had the tags in the wrong way. <br/>
Put all the wrong audio files in one directory, run the file and enter the path to the directory containing the incorrect tags, and it should be fixed. <br/>
My apologies for this (annoying) bug.

## :memo: License ##

This project is under license from GNUv3. For more details, see the [LICENSE](LICENSE) file.<br/>
I am not responsible for any legal consequences the user may or may not face by using this project.


Made with :heart: by <a href="https://github.com/JVT038" target="_blank">JVT038</a>

## To-Do

### Finished

- [X] Add support for the use of proxies to download YouTube videos
- [X] Add Docker support
- [X] Add Docker support for ARM64/v8 devices (such as Raspberry Pi 4)
- [X] Add Github action / workflow thing, to automatically create Docker image upon a new commit
- [X] Add support for Spotify
- [X] Add support for Deezer
- [X] Add support for Spotify as a metadata provider
- [X] Add support for Deezer as a metadata provider
- [X] Add support for Genius as a metadata provider
- [X] Add support for subpath (such as `localhost:5000/metatube`)
- [X] Add a nice progress bar
- [X] Add a function to allow users to download the song onto their device
Expand All @@ -230,8 +251,8 @@ Made with :heart: by <a href="https://github.com/JVT038" target="_blank">JVT038<
- [X] Dark mode support
- [X] Fix error `Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user’s experience. For more help http://xhr.spec.whatwg.org/` in overview
- [X] Make sure the search for downloaded song field works
### Not finished (I probably will never finish this)

### Not finished (I'll never finish this)

- [ ] Add it to the PyPi library
- [ ] Add support for sites other than YouTube
Expand All @@ -240,8 +261,9 @@ Made with :heart: by <a href="https://github.com/JVT038" target="_blank">JVT038<
- [ ] Add support for H.265 / HEVC
- [ ] Add authentication system with an optional reverse proxy
- [ ] Add support for TheAudioDB
- [ ] Add support for YouTube Music
- [ ] Add support for YouTube Music
- [ ] Add support for Last.fm!
- [ ] Add support for embedded lyrics (if possible)
- [ ] Add translations
- [ ] Add in-built file explorer, making manual paths optional
- [ ] Add some nice animations
Expand All @@ -256,13 +278,14 @@ Made with :heart: by <a href="https://github.com/JVT038" target="_blank">JVT038<
- [ ] Cache and store the segments and other video data, so next time of loading a video will be faster
- [ ] Send websocket requests to one specific device / client only, to prevent duplicate websocket requests
- [ ] Make sure the progress bar works properly in a Docker container, because it doesn't work properly rn.
- [ ] Use proper queues and threading during download instead of the weird ping-pong system between the client and the server.
&#xa0;

## Disclaimer

I made this project to educate myself about Python, and to learn how metadata works in combination with files.
Additionally, I want to emphasize I do NOT encourage any pirating, or any other illegal activities.
This project's purpose isn't to illegally download content from YouTube; its purpose is to educate and enlighten myself (and others viewing the source code) about Python, how Python interacts with metadata in files, and metadata works, and how yt-dlp works.
I am not responsible if the user downloads illegal content, or faces any (legal) consequences.


<a href="#top">Back to top</a>
5 changes: 4 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ class Config(object):
PORT = os.environ.get('PORT', 5000)
FFMPEG = os.environ.get('FFMPEG', "")
DOWNLOADS = os.environ.get('DOWNLOADS', os.path.join(basedir, 'downloads'))
URL_SUBPATH = os.environ.get('URL_SUBPATH', '/')
URL_SUBPATH = os.environ.get('URL_SUBPATH', '/')
META_EXTENSIONS = ['MP3', 'OPUS', 'FLAC', 'OGG', 'MP4', 'M4A', 'WAV']
VIDEO_EXTENSIONS = ['MP4', 'M4A', 'FLV', 'WEBM', 'OGG', 'MKV', 'AVI']
AUDIO_EXTENSIONS = ['AAC', 'FLAC', 'MP3', 'M4A', 'OPUS', 'VORBIS', 'WAV']
40 changes: 40 additions & 0 deletions fixartists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#################################
#####How to use this script:#####
#1. python fixartists.py#########
#2. Enter directory in CLI#######
#3. Let it run###################
#################################
from mutagen.easyid3 import EasyID3
from mutagen.flac import FLAC
from mutagen.oggopus import OggOpus
from mutagen.oggvorbis import OggVorbis
import os
directory = input('Enter relative or absolute path to audio files: ')
files = os.listdir(directory)
for file in files:
extensions = ['MP3', 'OPUS', 'FLAC', 'OGG']
filepath = os.path.join(directory, file)
extension = filepath.split('.')[len(filepath.split('.')) - 1].upper()
if os.path.isfile(filepath):
if extension.upper() in extensions:
if extension == 'MP3':
audio = EasyID3(filepath)
elif extension == 'OPUS':
audio = OggOpus(filepath)
elif extension == 'FLAC':
audio = FLAC(filepath)
elif extension == 'OGG':
audio = OggVorbis(filepath)
if 'artist' in audio:
old_artists = audio["artist"]
if len(old_artists) == 1 and '; ' in old_artists[0]:
new_artists = old_artists[0].split('; ')
audio["artist"] = new_artists
audio.save()
print(f'Fixed artists of {file}')
else:
print(f'{file} already has the correct artist format, skipping...')
else:
print(f'{file} contains no TPE1 tag, skipping')
else:
print(f'{file} has an unsupported extension, skipping')
18 changes: 17 additions & 1 deletion metatube/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Config(db.Model):
hardware_transcoding = db.Column(db.String(16), default="None")
metadata_sources = db.Column(db.String(128), default='deezer')
spotify_api = db.Column(db.String(128))
genius_api = db.Column(db.String(128))
auth = db.Column(db.Boolean, server_default=expression.false())
auth_username = db.Column(db.String(128))
auth_password = db.Column(db.String(128))
Expand All @@ -31,9 +32,15 @@ def set_amount(self, amount):

def set_spotify(self, spotify):
self.spotify_api = spotify
print(spotify)
db.session.commit()
logger.info('Changed the Spotify API settings')

def set_genius(self, genius):
self.genius_api = genius
db.session.commit()
logger.info('Changed the Genius API settings')

def set_metadata(self, metadata_sources):
self.metadata_sources = metadata_sources
db.session.commit()
Expand All @@ -50,6 +57,9 @@ def get_metadata_sources():
def get_spotify():
return Config.query.get(1).spotify_api

def get_genius():
return Config.query.get(1).genius_api

def get_max():
return Config.query.get(1).amount

Expand Down Expand Up @@ -177,7 +187,7 @@ def insert(data):
row = Database(
filepath = data["filepath"],
name = data["name"],
artist = data["artist"],
artist = '; '.join(data["artist"]),
album = data["album"],
date = parser.parse(data["date"]),
cover = data["image"],
Expand All @@ -203,6 +213,12 @@ def update(self, data):
logger.info('Updated item %s', data["name"])
data["date"] = data["date"].strftime('%d-%m-%Y')
sockets.overview({'msg': 'changed_metadata_db', 'data': data})

def updatefilepath(self, filepath):
self.filepath = filepath
db.session.commit()
logger.info('Updated filepath of item %s to %s', self.name, filepath)
sockets.overview({'msg': 'updated_filepath', 'filepath': filepath, 'item': self.id})

def delete(self):
db.session.delete(self)
Expand Down
26 changes: 26 additions & 0 deletions metatube/genius.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from lyricsgenius import Genius as geniusobj
from metatube import logger, sockets
class Genius():
def __init__(self, client_id):
try:
self.genius = geniusobj(client_id)
except TypeError() as e:
logger.error('Genius API failed: %s', str(e))

def search(self, data):
search = self.genius.search_songs(data["title"], data["max"])
sockets.geniussearch(search)
logger.info('Searched Genius for track \'%s\' ', data["title"])

def searchsong(data, token):
genius = Genius(token)
genius.search(data)

def fetchsong(self, id):
return self.genius.song(id)

def fetchlyrics(self, url):
return self.genius.lyrics(url)

def fetchalbum(self, id):
sockets.foundgeniusalbum(self.genius.album_tracks(id))
Loading