Exemple #1
0
def get_mp4_coverart(path):
    with open(path, 'rb') as f:
        data = f.read()
    cover = MP4Cover(data)
    return cover
Exemple #2
0
    def _save(self, filename, metadata):
        log.debug("Saving file %r", filename)
        file = MP4(encode_filename(self.filename))
        if file.tags is None:
            file.add_tags()
        tags = file.tags

        if config.setting["clear_existing_tags"]:
            tags.clear()

        for name, values in metadata.rawitems():
            if name.startswith('lyrics:'):
                name = 'lyrics'
            if name in self.__r_text_tags:
                tags[self.__r_text_tags[name]] = values
            elif name in self.__r_bool_tags:
                tags[self.__r_bool_tags[name]] = (values[0] == '1')
            elif name in self.__r_int_tags:
                try:
                    tags[self.__r_int_tags[name]] = [
                        int(value) for value in values
                    ]
                except ValueError:
                    pass
            elif name in self.__r_freeform_tags:
                values = [v.encode("utf-8") for v in values]
                tags[self.__r_freeform_tags[name]] = values
            elif name in self.__r_freeform_tags_ci:
                values = [v.encode("utf-8") for v in values]
                delall_ci(tags, self.__r_freeform_tags_ci[name])
                if name in self.__casemap:
                    name = self.__casemap[name]
                else:
                    name = self.__r_freeform_tags_ci[name]
                tags[name] = values
            elif name == "musicip_fingerprint":
                tags["----:com.apple.iTunes:fingerprint"] = [
                    b"MusicMagic Fingerprint%s" % v.encode('ascii')
                    for v in values
                ]

        if "tracknumber" in metadata:
            if "totaltracks" in metadata:
                tags["trkn"] = [(int(metadata["tracknumber"]),
                                 int(metadata["totaltracks"]))]
            else:
                tags["trkn"] = [(int(metadata["tracknumber"]), 0)]

        if "discnumber" in metadata:
            if "totaldiscs" in metadata:
                tags["disk"] = [(int(metadata["discnumber"]),
                                 int(metadata["totaldiscs"]))]
            else:
                tags["disk"] = [(int(metadata["discnumber"]), 0)]

        covr = []
        for image in metadata.images.to_be_saved_to_tags():
            if image.mimetype == "image/jpeg":
                covr.append(MP4Cover(image.data, MP4Cover.FORMAT_JPEG))
            elif image.mimetype == "image/png":
                covr.append(MP4Cover(image.data, MP4Cover.FORMAT_PNG))
        if covr:
            tags["covr"] = covr

        self._remove_deleted_tags(metadata, tags)

        file.save()
Exemple #3
0
def set_M4A_data(SONG_INFO, is_quiet, song_path, choice):
    """
    Set the tags in the m4a file passed.
    """
    cover_added = False

    try:
        # If more than one choice then call getChoice
        option = 0
        if len(SONG_INFO) > 1:
            if not is_quiet:
                option = getChoice(SONG_INFO, 'metadata')
            elif choice is not None and choice in range(1, len(SONG_INFO)):
                option = choice

        SONG_PATH = os.path.join(defaults.DEFAULT.SONG_TEMP_DIR, song_path)

        audio = MP4(SONG_PATH)

        # Download the cover image, if failed, pass
        if dwCover(SONG_INFO, option):
            imagedata = open(defaults.DEFAULT.COVER_IMG, 'rb').read()
            audio["covr"] = [
                MP4Cover(imagedata, imageformat=MP4Cover.FORMAT_JPEG)
            ]
            # REmove the image
            os.remove(defaults.DEFAULT.COVER_IMG)
            cover_added = True

        # If tags are not present then add them
        try:
            audio.add_tags()
        except Exception:
            pass

        audio.save()

        option = int(option)

        # Add the meta data, the key's can be found at
        # https://mutagen.readthedocs.io/en/latest/api/mp4.html#mutagen.mp4.MP4Tags
        audio["\xa9nam"] = SONG_INFO[option].track_name
        audio["\xa9alb"] = SONG_INFO[option].collection_name
        audio["\xa9ART"] = SONG_INFO[option].artist_name
        audio["\xa9day"] = SONG_INFO[option].release_date
        audio["\xa9gen"] = SONG_INFO[option].primary_genre_name

        # Adding track number would probably thwor some kind
        # of render error, will leave for later

        audio.save()

        defaults.DEFAULT.SONG_NAME_TO_SAVE = SONG_INFO[
            option].track_name + '.m4a'

        # Rename the downloaded file
        os.rename(
            SONG_PATH,
            os.path.join(defaults.DEFAULT.SONG_TEMP_DIR,
                         defaults.DEFAULT.SONG_NAME_TO_SAVE))

        return option, cover_added

    except Exception as e:
        return e
    def writeTags(self, mp4Path, artwork=True, thumbnail=False):
        self.log.info("Tagging file: %s." % mp4Path)
        ext = os.path.splitext(mp4Path)[1][1:]
        if ext not in valid_output_extensions:
            self.log.error("File is not the correct format.")
            sys.exit()

        video = MP4(mp4Path)
        try:
            video.delete()
            video.save()
        except IOError:
            self.log.debug(
                "Unable to clear original tags, attempting to proceed.")

        video["\xa9nam"] = self.title  # Movie title
        video["desc"] = self.shortdescription  # Short description
        video["ldes"] = self.description  # Long description
        video["\xa9day"] = self.date  # Year
        video["stik"] = [9]  # Movie iTunes category
        if self.HD is not None:
            video["hdvd"] = self.HD
        if self.genre is not None:
            genre = None
            for g in self.genre:
                if genre is None:
                    genre = g['name']
                    break
                # else:
                # genre += ", " + g['name']
            video["\xa9gen"] = genre  # Genre(s)
        video[
            "----:com.apple.iTunes:iTunMOVI"] = self.xml  # XML - see xmlTags method
        rating = self.rating()
        if rating is not None:
            video["----:com.apple.iTunes:iTunEXTC"] = rating

        if artwork:
            path = self.getArtwork(mp4Path)
            if path is not None:
                cover = open(path, 'rb').read()
                if path.endswith('png'):
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                     ]  # png poster
                else:
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                                     ]  # jpeg poster
        if self.original:
            video["\xa9too"] = "MDH:" + os.path.basename(self.original)
        else:
            video["\xa9too"] = "MDH:" + os.path.basename(mp4Path)

        for i in range(3):
            try:
                self.log.info("Trying to write tags.")
                video.save()
                self.log.info("Tags written successfully.")
                break
            except IOError as e:
                self.log.info("Exception: %s" % e)
                self.log.exception(
                    "There was a problem writing the tags. Retrying.")
                time.sleep(5)
Exemple #5
0
def convert_disc(inputfiles):
    first = min(inputfiles, key=int)
    last = max(inputfiles, key=int)

    print(first, last)

    offset = 150
    tracks = []

    for i in range(first, last + 1):
        with audioread.audio_open(str(inputfiles[i])) as f:
            t_sectors = int(f.duration * 75)
            tracks.append(Track(i, offset, t_sectors))
            offset += t_sectors

    disc_id = cddb_disc_info(tracks)
    disc_id[0] = format(disc_id[0], "x")
    disc_id = [str(x) for x in disc_id]

    query_cmd = "cddb query {}".format(" ".join(disc_id))
    query = requests.get(SERVER_URL, params={
        "cmd": query_cmd
    })

    print(query_cmd)

    if query.status_code != 200:
        return print("Error")

    query_lines = query.text.splitlines()
    query_status = int(query_lines[0].split(" ")[0])
    disc_category = ""

    if query_status == 200:
        category, match_id, dtitle = query_lines[0].split(" ", 3)[1:]

        question = {
            "type": "confirm",
            "name": "match",
            "message": "Found match: {}. Is this correct?".format(dtitle)
        }

        answer = prompt(question)

        if not answer["match"]:
            disc_category = "OTHER-NOT-LISTED"
        else:
            disc_category = category

    elif query_status == 210 or query_status == 211:
        question = {
            "type": "list",
            "name": "match",
            "message": "Multiple matches found, please select one",
            "choices": [
                {
                    "name": "Other (not listed)",
                    "value": "OTHER-NOT-LISTED"
                }
            ]
        }

        for i, match in enumerate(query_lines[1:-1]):
            category, match_id, dtitle = match.split(" ", 2)
            question["choices"].append({
                "name": dtitle,
                "value": category
            })

        answer = prompt(question)

        disc_category = answer["match"]

    if disc_category == "OTHER-NOT-LISTED" or query_status == 202:
        print("Could not find match in VGMDB CDDB.")

        question = {
            "type": "input",
            "name": "link",
            "message": "Please paste VGMDB ID, or leave blank to cancel:"
        }

        answer = prompt(question)

        vgmdb_link = answer["link"]
        disc_category = None

    if disc_category is None:

        vgmdb = requests.get("https://vgmdb.info/album/{}".format(vgmdb_link), params={
            "format": "json"
        })

        if vgmdb.status_code != 200:
            return print("Error")

        info = vgmdb.json()

        album = info["names"]["en"]
        if " / " in album:
            artist, album = info["names"]["en"].split(" / ", 1)
        else:
            artist = info["arrangers"][0]["names"]["en"]

        if " / " in album:
            album, artist = album.split(" / ", 1)

        art_get = requests.get(info["picture_full"])

        if len(info["covers"]) > 0:
            try:
                front_cover = next(filter(lambda c: c["name"] == "Front", info["covers"]))
                art_image = requests.get(front_cover["full"])
            except:
                art_image = requests.get(info["picture_full"])
        else:
            art_image = requests.get(info["picture_full"])

        if art_image.status_code == 200:
            cover = art_image.content

        if len(info["discs"]) > 1:
            disc_number = int(input("Disc number:")) - 1
            sdn = "y" in input("Save disc number?")
        else:
            disc_number = 0
            sdn = False

        tracks = info["discs"][disc_number]["tracks"]

        for i, track in enumerate(range(first, last + 1)):
            track_name = tracks[i]["names"]["Japanese"]
            try:
                track_name = tracks[i]["names"]["Romaji"]
            except KeyError:
                pass
            try:
                track_name = tracks[i]["names"]["English"]
            except KeyError:
                pass
            converted_filename = "output/{} – {}.m4a".format(track, track_name.replace("/", ""))
            convert_cmd = [
                "ffmpeg",
                "-y",
                "-i", inputfiles[track],
                "-c:a", "alac",
                "-c:v", "copy",
                converted_filename
            ]
            run(convert_cmd)

            audio = MP4(converted_filename)
            try:
                audio.delete(filename=converted_filename)
                audio.add_tags()
            except:
                pass

            audio.tags[TAGS["title"]] = track_name
            audio.tags[TAGS["artist"]] = artist
            audio.tags[TAGS["album"]] = album
            audio.tags[TAGS["genre"]] = "Anime"
            audio.tags[TAGS["year"]] = info["release_date"].split("-", 1)[0]
            audio.tags[TAGS["track"]] = ((track, last + 1 - first),)

            if sdn:
                audio.tags[TAGS["disc"]] = ((disc_number+1, len(info["discs"])),)

            if cover is not None:
                audio.tags[TAGS["cover"]] = (MP4Cover(cover, imageformat=MP4Cover.FORMAT_JPEG),)

            audio.save()

    else:

        read_cmd = "cddb read {} {}".format(disc_category, disc_id[0])
        read = requests.get(SERVER_URL, params={
            "cmd": read_cmd
        })

        if query.status_code != 200:
            return print("Error")

        read_lines = read.text.splitlines()
        read_status = int(read_lines[0].split(" ")[0])

        if read_status == 210:
            data = {}
            for line in read_lines[1:-1]:
                if line.startswith("#"): continue
                k, v = line.strip().split('=')
                data[k] = v

            artist, album = data["DTITLE"].split(" / ", 1)
            catalog, album = album.split(" ", 1)
            catalog = catalog[1:-1]

            if " / " in album:
                album, artist = album.split(" / ", 1)

            art_search = requests.get("https://vgmdb.info/search/albums", params={
                "format": "json",
                "q": catalog
            })

            cover = None

            if art_search.status_code == 200:
                results = art_search.json()["results"]["albums"]

                if len(results) > 0:
                    art_get = requests.get("https://vgmdb.info/{}".format(results[0]["link"]))

                    if art_get.status_code == 200:
                        try:
                            results_json = art_get.json()
                            if len(results_json["covers"]) > 0:
                                try:
                                    front_cover = next(filter(lambda c: c["name"] == "Front", results_json["covers"]))
                                    art_image = requests.get(front_cover["full"])
                                except:
                                    art_image = requests.get(info["picture_full"])
                            else:
                                art_image = requests.get(results_json["picture_full"])

                            if art_image.status_code == 200:
                                cover = art_image.content
                        except:
                            pass

            for i, track in enumerate(range(first, last + 1)):
                converted_filename = "output/{} – {}.m4a".format(track, data["TTITLE{}".format(i)].replace("/", ""))
                convert_cmd = [
                    "ffmpeg",
                    "-y",
                    "-i", inputfiles[track],
                    "-c:a", "alac",
                    "-c:v", "copy",
                    converted_filename
                ]
                run(convert_cmd)

                audio = MP4(converted_filename)
                try:
                    audio.delete(filename=converted_filename)
                    audio.add_tags()
                except:
                    pass

                audio.tags[TAGS["title"]] = data["TTITLE{}".format(i)]
                audio.tags[TAGS["artist"]] = artist
                audio.tags[TAGS["album"]] = album
                audio.tags[TAGS["genre"]] = "Anime"
                audio.tags[TAGS["year"]] = data["DYEAR"]
                audio.tags[TAGS["track"]] = ((track, last + 1 - first),)

                if cover is not None:
                    audio.tags[TAGS["cover"]] = (MP4Cover(cover, imageformat=MP4Cover.FORMAT_JPEG),)

                audio.save()
    def writeTags(self, mp4Path, artwork=True, thumbnail=False):
        self.log.info("Tagging file: %s." % mp4Path)
        ext = os.path.splitext(mp4Path)[1][1:]
        if ext not in valid_tagging_extensions:
            self.log.error("File is not the correct format.")
            return False

        video = MP4(mp4Path)
        checktags = {}
        checktags["tvsh"] = self.show  # TV show title
        checktags["\xa9nam"] = self.title  # Video title
        checktags["tven"] = self.title  # Episode title
        checktags["desc"] = self.shortDescription()  # Short description
        checktags[
            "ldes"] = self.description  # Long description (same a short for tv)
        network = [x['name'] for x in self.network]
        checktags["tvnn"] = network  # Network
        if self.airdate != "0000-00-00":
            checktags["\xa9day"] = self.airdate  # Airdate
        checktags["tvsn"] = [self.season]  # Season number
        checktags["disk"] = [(int(self.season), 0)],
        checktags["disk"] = [(int(self.season), 0)]  # Season number as disk
        checktags["\xa9alb"] = self.show + ", Season " + str(
            self.season)  # iTunes Album as Season
        checktags["tves"] = [self.episode]  # Episode number
        checktags["trkn"] = [(int(self.episode), len(self.seasondata))
                             ]  # Episode number iTunes
        #checktags["stik"] = [10]  # TV show iTunes category
        #if self.HD is not None:
        #    checktags["hdvd"] = self.HD
        if self.genre is not None:
            genre = None
            for g in self.genre:
                if genre is None:
                    genre = g['name']
                    break
            checktags["\xa9gen"] = genre
            # video["\xa9gen"] = self.genre.replace('|', ',')[1:-1]  # Genre(s)
        #checktags["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode("UTF-8", errors="ignore")  # XML - see xmlTags method
        # video["----:com.apple.iTunes:iTunEXTC"] = self.setRating()  # iTunes content rating

        if artwork:
            path = self.getArtwork(mp4Path, thumbnail=thumbnail)
            if path is not None:
                cover = open(path, 'rb').read()
                if path.endswith('png'):
                    checktags["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                         ]  # png poster
                else:
                    checktags["covr"] = [
                        MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                    ]  # jpeg poster

        ProcessTags = False
        for keys, values in checktags.items():
            if video.tags == None:
                ProcessTags = True
                break
            elif keys in video.tags:
                if video.tags[keys] != [values]:
                    self.log.debug(keys +
                                   " tag does not match and will be updated")
                    ProcessTags = True
                    break
            else:
                self.log.debug(keys + " will be added")
                ProcessTags = True
        if not ProcessTags:
            self.log.info("All MP4 tags match the original, skipping tagging.")
        else:
            try:
                video.delete()
            except IOError:
                self.log.debug(
                    "Unable to clear original tags, attempting to proceed.")

            video["tvsh"] = self.show  # TV show title
            video["\xa9nam"] = self.title  # Video title
            video["tven"] = self.title  # Episode title
            video["desc"] = self.shortDescription()  # Short description
            video[
                "ldes"] = self.description  # Long description (same a short for tv)
            network = [x['name'] for x in self.network]
            video["tvnn"] = network  # Network
            if self.airdate != "0000-00-00":
                video["\xa9day"] = self.airdate  # Airdate
            video["tvsn"] = [self.season]  # Season number
            video["disk"] = [(int(self.season), 0)]  # Season number as disk
            video["\xa9alb"] = self.show + ", Season " + str(
                self.season)  # iTunes Album as Season
            video["tves"] = [self.episode]  # Episode number
            video["trkn"] = [(int(self.episode), len(self.seasondata))
                             ]  # Episode number iTunes
            #video["stik"] = [10]  # TV show iTunes category
            #if self.HD is not None:
            #    video["hdvd"] = self.HD
            if self.genre is not None:
                genre = None
                for g in self.genre:
                    if genre is None:
                        genre = g['name']
                        break
                video["\xa9gen"] = genre
                # video["\xa9gen"] = self.genre.replace('|', ',')[1:-1]  # Genre(s)
            #video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode("UTF-8", errors="ignore")  # XML - see xmlTags method
            # video["----:com.apple.iTunes:iTunEXTC"] = self.setRating()  # iTunes content rating

            if artwork:
                path = self.getArtwork(mp4Path, thumbnail=thumbnail)
                if path is not None:
                    cover = open(path, 'rb').read()
                    if path.endswith('png'):
                        video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                         ]  # png poster
                    else:
                        video["covr"] = [
                            MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                        ]  # jpeg poster
            if self.original:
                video["\xa9too"] = "MDH:" + os.path.basename(self.original)
            else:
                video["\xa9too"] = "MDH:" + os.path.basename(mp4Path)
            MP4(mp4Path).delete(mp4Path)
            for i in range(3):
                try:
                    self.log.info("Trying to write tags.")
                    video.save()
                    self.log.info("Tags written successfully.")
                    return True
                except IOError as e:
                    self.log.exception(
                        "There was a problem writing the tags. Retrying.")
                    time.sleep(5)
            return False
Exemple #7
0
    def TagTrack(self, folder, export=''):
        '''
            'Tag' a song's trackdata with the infomation given in folder

            Call once all download tasks is finished

            Suppports MP3,M4A(ALAC/MP4),FLAC
        '''

        export = export if export else self.output
        folder = str(folder)
        audio = [
            f for f in os.listdir(folder)
            if f.split('.')[-1].lower() in ['mp3', 'm4a', 'flac', 'ogg']
        ]
        if not audio:
            logger.error(
                'Supported audio file for %s is missing,Cannot continue formatting!'
                % folder)
            return
        audio = audio[-1]
        audio = self.GenerateDownloadPath(filename=audio, folder=folder)
        format = audio.split('.')[-1].lower()
        # Locate audio file,uses last match
        track = self.GenerateDownloadPath(filename='track.json', folder=folder)
        # Locate track file
        cover = self.GenerateDownloadPath(filename='cover.jpg', folder=folder)
        # Locate cover image

        track = json.loads(open(track, encoding='utf-8').read())
        tHelper = TrackHelper(track)

        def write_keys(song):
            # Write trackdatas
            song['title'] = tHelper.TrackName
            song[
                'artist'] = tHelper.Artists if tHelper.Artists else 'Various Artists'
            song[
                'album'] = tHelper.AlbumName if tHelper.AlbumName else 'Unknown'
            song['tracknumber'] = str(tHelper.TrackNumber)
            song['date'] = str(tHelper.TrackPublishTime)
            song.save()

        if format == 'm4a':
            # Process m4a files: Apple’s MP4 (aka M4A, M4B, M4P)
            song = easymp4.EasyMP4(audio)
            write_keys(song)
            if os.path.exists(cover):
                song = MP4(audio)
                # Write cover image
                song['covr'] = [MP4Cover(open(cover, 'rb').read())]
                song.save()
        elif format == 'mp3':
            # Process mp3 files: MPEG audio stream information and tags
            song = EasyMP3(audio)
            write_keys(song)
            if os.path.exists(cover):
                song = ID3(audio)
                # Write cover image
                song.add(
                    APIC(encoding=3,
                         mime='image/jpeg',
                         type=3,
                         desc='Cover',
                         data=open(cover, 'rb').read()))
                song.save()
        elif format == 'flac':
            # Process FLAC files:Free Lossless Audio Codec
            song = FLAC(audio)
            write_keys(song)
            if os.path.exists(cover):
                pic = Picture()
                pic.data = open(cover, 'rb').read()
                pic.mime = 'image/jpeg'
                song.add_picture(pic)
                song.save()
        elif format == 'ogg':
            # Process OGG files:Ogg Encapsulation Format
            song = OggVorbis(audio)
            write_keys(song)
            if os.path.exists(cover):
                pic = Picture()
                pic.data = open(cover, 'rb').read()
                pic.mime = 'image/jpeg'
                song["metadata_block_picture"] = [
                    base64.b64encode(pic.write()).decode('ascii')
                ]
                song.save()
        # Rename & move file
        savename = tHelper.SanitizedTitle + '.' + format
        try:
            path = self.GenerateDownloadPath(filename=savename, folder=export)
            shutil.copy(audio, path)
            logger.debug('Exported audio to path %s' % path[-truncate_length:])
            return path
        except Exception as e:
            raise Exception('While copying audio file:%s' % e)
Exemple #8
0
    def FormatSong(self, folder, export=''):
        '''
            'Format' a song's metadata with the infomation given in folder

            Call once all download tasks is finished

            Suppports MP3,M4A(ALAC/MP4),FLAC
        '''
        export = export if export else self.output
        folder = str(folder)
        audio = [
            f for f in os.listdir(folder)
            if f.split('.')[-1] in ['mp3', 'm4a', 'flac']
        ]
        if not audio: return
        audio = audio[-1]
        audio = self.GenerateDownloadPath(filename=audio, folder=folder)
        format = audio.split('.')[-1]
        # Locate audio file,uses last match
        meta = self.GenerateDownloadPath(filename='meta.json', folder=folder)
        # Locate meta file
        cover = self.GenerateDownloadPath(filename='cover.jpg', folder=folder)
        # Locate cover image

        if not audio:
            self.log('audio.m4a / audio.mp3 / audio.flac',
                     format=strings.ERROR_FILE_MISSING)
            return
        if not os.path.exists(meta):
            self.log('meta.json', format=strings.ERROR_FILE_MISSING)
            return
        if not os.path.exists(cover):
            self.log('cover.jpg', format=strings.WARN_FILE_MISSING)

        meta = json.loads(open(meta, encoding='utf-8').read())

        def write_keys(song):
            # Write metadatas
            song['title'] = meta['title']
            song['artist'] = meta['author']
            song['album'] = meta['album']
            song.save()

        if format == 'm4a':
            # Process m4a files: Apple’s MP4 (aka M4A, M4B, M4P)
            song = easymp4.EasyMP4(audio)
            write_keys(song)
            if os.path.exists(cover):
                song = MP4(audio)
                # Write cover image
                song['covr'] = [MP4Cover(open(cover, 'rb').read())]
                song.save()
        elif format == 'mp3':
            # Process mp3 files: MPEG audio stream information and tags
            song = EasyMP3(audio)
            write_keys(song)
            if os.path.exists(cover):
                song = ID3(audio)
                # Write cover image
                song.add(
                    APIC(encoding=3,
                         mime='image/jpeg',
                         type=3,
                         desc='Cover',
                         data=open(cover, 'rb').read()))
                song.save()
        elif format == 'flac':
            # Process FLAC files:Free Lossless Audio Codec
            song = FLAC(audio)
            write_keys(song)
            if os.path.exists(cover):
                pic = Picture()
                pic.data = open(cover, 'rb').read()
                pic.mime = 'image/jpeg'
                song.add_picture(pic)
                song.save()

        # Rename & move file
        savename = '{1} - {0}.{2}'.format(meta['title'], meta['author'],
                                          format)
        try:
            path = self.GenerateDownloadPath(filename=savename, folder=export)
            shutil.copy(audio, path)
            self.log(path, format=strings.INFO_EXPORT_COMPLETE)
        except Exception as e:
            self.log(e, format=strings.ERROR_INVALID_OPERATION)
        return path
Exemple #9
0
song_path = 'C:/Users/Lomzem/Desktop/newest-songs/'

abspath_song = lambda file: song_path + file
abspath_art = lambda file: artwork_path + file

def get_pairs():
	pair_list = []

	for song_file in os.listdir(song_path):
		song_file_name, song_file_ext = os.path.splitext(song_file)

		for art_file in os.listdir(artwork_path):
			art_file_name, art_file_ext = os.path.splitext(art_file)

			if song_file_name == art_file_name:
				complete_pair = (abspath_song(song_file), abspath_art(art_file))
				pair_list.append(complete_pair)

	return pair_list

pair_list = get_pairs()

for pair in pair_list:
	song_file, art_file = pair

	audio = MP4(song_file)
	with open(art_file, 'rb') as f:
		audio['covr'] = [
			MP4Cover(f.read())
		]
	audio.save()
Exemple #10
0
def downloadSong(web_url,baseFolder,file,performance,username):
    # Construct full path to filename
    filename = baseFolder + file

    # If the file already exists, skip it
    if path.exists(filename):
        print(f"ALREADY EXISTS - {filename}")
        return 0

    # Print filename
    print(f"Downloading {filename}")

    try:
        # Print out the web_url for debugging purposes
        # TODO: Convert to debug message?
        #print(web_url)
        # The web_url returns an HTML page that contains the link to the content we wish to download
        with request.urlopen(web_url) as url:
            # First get the HTML for the web_url
            htmlstr = str(url.read())
            #print(htmlstr)
            # Next, parse out the actual media_url, which is in the content field of the "twitter:player:stream" object
            # We need to strip out the "amp;" values and convert the "+" value to URL-friendly value
            media_url = unquote(re.search('twitter:player:stream.*?content=".*?"',htmlstr).group(0).split('"')[2]).replace("amp;","").replace("+","%2B")
            #print(media_url)
            # Print out the media_url for debugging purposes
            # TODO: Convert this to a debug message?
            #print(media_url)

            # Open the file in binary write mode and write the data from the media_url
            f = open(filename,'w+b')
            f.write(request.urlopen(media_url).read())
            f.close()
    except Exception as e:
        print("FAILED TO DOWNLOAD!!!!!!!!!!!!!!")
        if "'NoneType' object has no attribute 'group'" in str(e):
            print("Recording not available - attempting to play in order to make it available")
            media_url = unquote(re.search('twitter:player" content=".*?"',htmlstr).group(0).split('"')[2]).replace("amp;","").replace("+","%2B")
            # webbrowser registration does not seem to be needed
            #webbrowser.register('chrome',None,webbrowser.BackgroundBrowser("C://Program Files (x86)//Google//Chrome//Application//chrome.exe"))
            #webbrowser.get('chrome').open(media_url)
            webbrowser.open(media_url)
            #print(f"NEED TO PLAY: {media_url}")
        else:
            print(str(e))
        print("-----")
        #if (not "HTTP Error 504" in str(e)) and (not "HTTP Error 410" in str(e)) and (not "'NoneType' object has no attribute 'group'" in str(e)):
            #raise
        return 1

    try:
        # Calculate necessary dates
        createdat = performance["created_at"]
        perfdate = datetime.strptime(createdat[0:10],"%Y-%m-%d")
        # Set the album date to the start of the week on which the song was created
        albumdate = (perfdate - timedelta(days=perfdate.weekday())).strftime("%Y-%m-%d")
        albumyear = createdat[0:4]
        # Write the tags for the M4A file
        af = MP4(filename)
        af["\xa9nam"] = performance["fixed_title"]
        af["\xa9ART"] = performance["performers"]
        # Set Album Artist to the username we searched for
        af["aART"] = username
        # Android seems to have a bug where wrong art is displayed if "Album" tag is empty so set it to "Smule" followed by current date
        af["\xa9alb"] = f"Smule - {albumdate}"
        af["\xa9day"] = f"{albumyear}"
        af["purd"] = createdat
        af["\xa9cmt"] = f"Performed on {createdat}"

        # Write the JPEG to the M4A file as album cover. Ignore any errors reading the image
        try:
            pic_url = performance['display_pic_url']
            img = MP4Cover(request.urlopen(pic_url).read(), imageformat=MP4Cover.FORMAT_JPEG)
            af["covr"] = [img]
        except:
            pass
        # Save the updated tags to the file
        af.save()
    except Exception as e:
        print("FAILED TO UPDATE TAGS!!!")
        print(str(e))
        return 0

    # Print pic URL for debugging purposes
    # print(pic_url)
    return 0
Exemple #11
0
	def tagFile(self, filename, metadata, art_url):
		if not self.file_done:
			return
		image = None
		if art_url is not None:
			self.getFile('artwork.jpg', art_url, True)
			try:
				with open('artwork.jpg', 'rb') as file:
					image = file.read()
			except:
				pass
		if filename.endswith('.mp3'):
			audio = MP3(filename, ID3=ID3)
			try:
				audio.add_tags()
			except:
				pass
			if image:
				audio.tags.add(
					APIC(
						encoding=3,
						mime='image/jpeg',
						type=3,
						desc=u'Cover',
						data=image
					)
				)
			audio.tags["TIT2"] = TIT2(encoding=3, text=(metadata.get('title', '')))
			try:
				audio.tags["TPE1"] = TPE1(encoding=3, text=metadata.get('artist', ''))
			except:
				pass
			audio.tags["TDRC"] = TDRC(encoding=3, text=(metadata.get('year', '')))
			audio.tags["TCON"] = TCON(encoding=3, text=(metadata.get('genre', ' ')))
			audio.save()
		elif filename.endswith('.flac'):
			audio = FLAC(filename)
			try:
				audio.add_tags()
			except:
				pass
			audio.tags['title'] = metadata['title']
			audio.tags['artist'] = metadata['artist']
			audio.tags['year'] = metadata['year']
			audio.tags['genre'] = metadata['genre']
			audio.tags.add(
				APIC(
					encoding=3,
					mime='image/jpeg',
					type=3,
					desc=u'Cover',
					data=image
				)
			)
			audio.save()
		elif filename.endswith('.m4a'):
			audio = MP4(filename)
			try:
				audio.add_tags()
			except:
				pass
			covr = []
			covr.append(MP4Cover(image, MP4Cover.FORMAT_JPEG))
			audio.tags['covr'] = covr
			audio.tags['title'] = metadata['title']
			audio.tags['artist'] = metadata['artist']
			#audio.tags['year'] = metadata['year']
			audio.tags['genre'] = metadata['genre']
			audio.save()
		if os.path.isfile('artwork.jpg'):
			os.remove('artwork.jpg')
Exemple #12
0
def start_process(filenames, mode):
    """
    This is the main funtion of the script
    where it does its main processing.\n
    filenames is the list of files to be processed\n
    mode = 1,2,3 or 4\n
    1 means mp4 to tagged mp4\n
    2 means mp4 with sub to subbed and tagged mp4\n
    3 means mkv to tagged mp4\n
    4 means mkv with sub to subbed and tagged mp4
    """

    for filename in filenames:
        try:
            title = filename[:-4]
            
            stream_md = collect_stream_metadata(filename)
            streams_to_process = []
            dvdsub_exists=False
            for stream in stream_md['streams']:
                if not stream['codec_name'] in sub_codec_blacklist:
                    streams_to_process.append(stream['index'])
                else:
                    dvdsub_exists=True
            
            print('\nSearching IMDb for "{}"'.format(title))
            
            imdb = Imdb()
            movie_results = []
            results = imdb.search_for_title(title)
            for result in results:
                if result['type'] == "feature":
                    movie_results.append(result)
                    
            if not movie_results:
                while not movie_results:
                    title = input('\nNo results for "' + title +
                                  '" Enter alternate/correct movie title >> ')
                    
                    results = imdb.search_for_title(title)
                    for result in results:
                        if result['type'] == "feature":
                            movie_results.append(result)
                
            # The most prominent result is the first one
            # mpr - Most Prominent Result
            mpr = movie_results[0]
            print('\nFetching data for {} ({})'.format(mpr['title'],
                                                       mpr['year']))
                                                     
            # imdb_movie is a dict of info about the movie
            imdb_movie = imdb.get_title(mpr['imdb_id'])
            
            imdb_movie_title = imdb_movie['base']['title']
            imdb_movie_year = imdb_movie['base']['year']
            imdb_movie_id = mpr['imdb_id']
                        
            
            imdb_movie_rating = imdb_movie['ratings']['rating']
            
            if not 'outline' in imdb_movie['plot']:
                imdb_movie_plot_outline = (imdb_movie['plot']['summaries'][0]
                                           ['text'])
                print("\nPlot outline does not exist. Fetching plot summary "
                        "instead.\n\n")
            else:
                imdb_movie_plot_outline = imdb_movie['plot']['outline']['text']
            
            # Composing a string to have the rating and the plot of the
            # movie which will go into the 'comment' metadata of the 
            # mp4 file.
            imdb_rating_and_plot = str('IMDb rating ['
                                       + str(float(imdb_movie_rating))
                                       + '/10] - '
                                       + imdb_movie_plot_outline)
                                       
            
            imdb_movie_genres = imdb.get_title_genres(imdb_movie_id)['genres']
            
            # Composing the 'genre' string of the movie.
            # I use ';' as a delimeter to searate the multiple genre values
            genre = ';'.join(imdb_movie_genres)
            
            
            newfilename = (imdb_movie_title
                           + ' ('
                           + str(imdb_movie_year)
                           + ').mp4')
                           
            # We don't want the characters not allowed in a filename
            newfilename = (newfilename
                           .replace(':', ' -')
                           .replace('/', ' ')
                           .replace('?', ''))

            command = ""
            stream_map = []
            for f in streams_to_process:
                stream_map.append("-map 0:{}".format(f))
            stream_map_str = ' '.join(stream_map)           
            
            

            if mode == 1:
                # it is required to rename it as its already an mp4 file that
                # wasn't proccessed by ffmpeg
                os.rename(filename, newfilename)
            if mode == 2 or mode == 4:

                command = ('ffmpeg -i "'
                           + filename
                           + '" -sub_charenc UTF-8 -i "'
                           + filename[:-4]
                           + '.srt" '
                           + stream_map_str
                           + ' -map 1 -c copy -c:s mov_text '
                             '"' + newfilename + '"')
                subprocess.run(shlex.split(command))
            if mode == 3:
                command = ('ffmpeg -i '
                           + '"' + filename + '" '
                           + stream_map_str
                           + ' -c copy -c:s mov_text '
                             '"' + newfilename + '"')
                subprocess.run(shlex.split(command))
                
            if dvdsub_exists:
                print("\nRemoved DVD Subtitles due to uncompatibility with "
                      "mp4 file format")

            # The poster is fetched from tmdb only if there is no file
            # named " filename + '.jpg' " in the working directory
            # this way user can provide their own poster image to be used
            poster_filename = filename[:-4] + '.jpg'
            if not os.path.isfile(poster_filename):
                print('\nFetching the movie poster...')
                tmdb_find = tmdb.Find(imdb_movie_id)
                tmdb_find.info(external_source = 'imdb_id')
                
                path = tmdb_find.movie_results[0]['poster_path']
                complete_path = r'https://image.tmdb.org/t/p/w780' + path
                
                uo = urllib.request.urlopen(complete_path)
                with open(poster_filename, "wb") as poster_file:
                    poster_file.write(uo.read())
                    poster_file.close()
            
            

            video = MP4(newfilename)
            with open(poster_filename, "rb") as f:
                video["covr"] = [MP4Cover(
                                    f.read(),
                                    imageformat=MP4Cover.FORMAT_JPEG)]
                video['\xa9day'] = str(imdb_movie_year)
                video['\xa9nam'] = imdb_movie_title
                video['\xa9cmt'] = imdb_rating_and_plot
                video['\xa9gen'] = genre
                print('\nAdding poster and tagging file...')

            try:
                video.save()
                #  I have encounterd this error in pevious version
                #  of script, now I handle it by removing the metadata
                #  of the file. That seems to solve the probelem
            except OverflowError:
                remove_meta_command = ('ffmpeg -i "' + newfilename
                                       + '" -codec copy -map_metadata -1 "'
                                       + newfilename[:-4] + 'new.mp4"')
                subprocess.run(shlex.split(remove_meta_command))
                video_new = MP4(newfilename[:-4] + 'new.mp4')
                with open(poster_filename, "rb") as f:
                    video_new["covr"] = [MP4Cover(
                                            f.read(),
                                            imageformat=MP4Cover.FORMAT_JPEG)]
                    video_new['\xa9day'] = str(imdb_movie_year)
                    video_new['\xa9nam'] = imdb_movie_title
                    video_new['\xa9cmt'] = imdb_rating_and_plot
                    video_new['\xa9gen'] = genre
                    print('\nAdding poster and tagging file...')

                try:
                    video_new.save()
                    if not os.path.exists('auto fixed files'):
                        os.makedirs('auto fixed files')
                    os.rename(newfilename[:-4]
                              + 'new.mp4', 'auto fixed files\\'
                              + newfilename[:-4] + '.mp4')
                    os.remove(newfilename)

                except OverflowError:
                    errored_files.append(filename
                                         + (' - Could not save even after'
                                            'striping metadata'))
                    continue

            os.remove(poster_filename)
            print('\n' + filename
                       + (' was proccesed successfuly!\n\n===================='
                          '======================================'))
        except Exception as e:
            print('\nSome error occured while processing '
                  + filename
                  + '\n\n====================================================')
            errored_files.append(filename + ' - ' + str(e))
            PrintException()
Exemple #13
0
    def writeTags(self, mp4Path, artwork=True, thumbnail=False):
        self.log.debug("Tagging file %s" % mp4Path)
        if MkvtoMp4(self.settings).validSource(mp4Path) == True:
            video = MP4(mp4Path)
            try:
                video.delete()
            except IOError:
                self.log.debug(
                    "Unable to clear original tags, attempting to proceed")

            video["\xa9nam"] = self.title  # Movie title
            #video["desc"] = self.shortdescription  # Short description
            #video["ldes"] = self.description  # Long description
            video["\xa9day"] = self.date  # Year
            #video["stik"] = [9]  # Movie iTunes category
            if self.HD is not None:
                video["hdvd"] = self.HD
            #if self.genre is not None:
            #    genre = None
            #    for g in self.genre:
            #        if genre is None:
            #            genre = g['name']
            #            break
            #        # else:
            #            # genre += ", " + g['name']
            #    video["\xa9gen"] = genre  # Genre(s)
            #video["----:com.apple.iTunes:iTunMOVI"] = self.xml  # XML - see xmlTags method
            #rating = self.rating()
            #if rating is not None:
            #    video["----:com.apple.iTunes:iTunEXTC"] = rating

            if artwork:
                path = self.getArtwork(mp4Path)
                if path is not None:
                    cover = open(path, 'rb').read()
                    if path.endswith('png'):
                        video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                         ]  # png poster
                    else:
                        video["covr"] = [
                            MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                        ]  # jpeg poster

            #if self.original:
            #    video["\xa9too"] = ("meks-ffmpeg movie [%s-%s]" % (self.provider, self.providerid))
            #else:
            #    video["\xa9too"] = ("meks-ffmpeg movie [%s-%s]" % (self.provider, self.providerid))
            video = metadata_stamper.stamp_encoder(
                video=video,
                save=False,
                stamp=("movie [%s-%s]" % (self.provider, self.providerid)))

            for i in range(3):
                try:
                    self.log.debug("Trying to write tags")
                    video.save()
                    self.log.info("Tags written successfully")
                    return True
                except IOError as e:
                    self.log.exception(
                        "There was a problem writing the tags. Retrying")
                    time.sleep(5)
        else:
            self.log.error("The file is invalid")
        raise IOError
Exemple #14
0
    def writeTags(self,
                  path,
                  artwork=True,
                  thumbnail=False,
                  width=None,
                  height=None):
        self.log.info("Tagging file: %s." % path)
        if width and height:
            try:
                self.setHD(width, height)
            except:
                self.log.exception("Unable to set HD tag.")

        try:
            video = MP4(path)
        except MP4StreamInfoError:
            self.log.error(
                'File is not a valid MP4 file and cannot be tagged.')
            return False

        try:
            video.delete()
        except:
            self.log.debug("Unable to clear original tags, will proceed.")

        if self.mediatype == MediaType.Movie:
            video["\xa9nam"] = self.title  # Movie title
            video["desc"] = self.tagline  # Short description
            video["ldes"] = self.description  # Long description
            video["\xa9day"] = self.date  # Year
            video["stik"] = [9]  # Movie iTunes category
        elif self.mediatype == MediaType.TV:
            video["tvsh"] = self.showname  # TV show title
            video["\xa9nam"] = self.title  # Video title
            video["tven"] = self.title  # Episode title
            video["desc"] = self.shortDescription  # Short description
            video["ldes"] = self.description  # Long description
            network = [x['name'] for x in self.network]
            video["tvnn"] = network  # Network
            video["\xa9day"] = self.airdate  # Airdate
            video["tvsn"] = [self.season]  # Season number
            video["disk"] = [(self.season, 0)]  # Season number as disk
            video["\xa9alb"] = self.showname + ", Season " + str(
                self.season)  # iTunes Album as Season
            video["tves"] = [self.episode]  # Episode number
            video["trkn"] = [
                (self.episode, len(self.seasondata.get('episodes', [])))
            ]  # Episode number iTunes
            video["stik"] = [10]  # TV show iTunes category

        if self.HD:
            video["hdvd"] = self.HD
        if self.genre and len(self.genre) > 0:
            video["\xa9gen"] = self.genre[0].get('name')
        video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode(
            "UTF-8", errors="ignore")  # XML - see xmlTags method
        if self.rating:
            video["----:com.apple.iTunes:iTunEXTC"] = self.rating.encode(
                "UTF-8", errors="ignore")  # iTunes content rating

        if artwork:
            coverpath = self.getArtwork(path, thumbnail=thumbnail)
            if coverpath is not None:
                cover = open(coverpath, 'rb').read()
                if path.endswith('png'):
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                     ]  # png poster
                else:
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                                     ]  # jpeg poster

        if self.original:
            video["\xa9too"] = "SMA:" + os.path.basename(self.original)
        else:
            video["\xa9too"] = "SMA:" + os.path.basename(path)

        try:
            self.log.info("Trying to write tags.")
            video.save()
            self.log.info("Tags written successfully.")
            return True
        except:
            self.log.exception("There was an error writing the tags.")
        return False
Exemple #15
0
def tag(tHelper: TrackHelper, audio: str, cover: str):
    from mutagen.flac import FLAC, Picture
    from mutagen.id3 import ID3, APIC
    from mutagen.mp3 import EasyMP3
    from mutagen import easymp4
    from mutagen.mp4 import MP4, MP4Cover
    from mutagen.oggvorbis import OggVorbis

    def write_keys(song):
        # Write trackdatas
        song['title'] = tHelper.TrackName
        song['artist'] = tHelper.Artists
        song['album'] = tHelper.AlbumName
        song['tracknumber'] = str(tHelper.TrackNumber)
        song['date'] = str(tHelper.TrackPublishTime)
        song.save()

    format = audio.split('.')[-1].lower()
    if format == 'm4a':
        # Process m4a files: Apple’s MP4 (aka M4A, M4B, M4P)
        song = easymp4.EasyMP4(audio)
        write_keys(song)
        if exists(cover):
            song = MP4(audio)
            # Write cover image
            song['covr'] = [MP4Cover(open(cover, 'rb').read())]
            song.save()
    elif format == 'mp3':
        # Process mp3 files: MPEG audio stream information and tags
        song = EasyMP3(audio)
        write_keys(song)
        if exists(cover):
            song = ID3(audio)
            # Write cover image
            song.add(
                APIC(encoding=3,
                     mime='image/jpeg',
                     type=3,
                     desc='Cover',
                     data=open(cover, 'rb').read()))
            song.save()
    elif format == 'flac':
        # Process FLAC files:Free Lossless Audio Codec
        song = FLAC(audio)
        write_keys(song)
        if exists(cover):
            pic = Picture()
            pic.data = open(cover, 'rb').read()
            pic.mime = 'image/jpeg'
            song.add_picture(pic)
            song.save()
    elif format == 'ogg':
        # Process OGG files:Ogg Encapsulation Format
        song = OggVorbis(audio)
        write_keys(song)
        if exists(cover):
            pic = Picture()
            pic.data = open(cover, 'rb').read()
            pic.mime = 'image/jpeg'
            song["metadata_block_picture"] = [
                base64.b64encode(pic.write()).decode('ascii')
            ]
            song.save()
    return True
Exemple #16
0
    def as_m4a(self):
        """ Embed metadata to M4A files. """
        # Apple has specific tags - see mutagen docs -
        # http://mutagen.readthedocs.io/en/latest/api/mp4.html
        tags = {
            'album': '\xa9alb',
            'artist': '\xa9ART',
            'date': '\xa9day',
            'title': '\xa9nam',
            'originaldate': 'purd',
            'comment': '\xa9cmt',
            'group': '\xa9grp',
            'writer': '\xa9wrt',
            'genre': '\xa9gen',
            'tracknumber': 'trkn',
            'albumartist': 'aART',
            'disknumber': 'disk',
            'cpil': 'cpil',
            'albumart': 'covr',
            'copyright': 'cprt',
            'tempo': 'tmpo',
            'lyrics': '\xa9lyr',
            'publisher':
            '----:com.apple.iTunes:publisher',  #equals to label for NI Traktor
            'audiotype':
            '----:com.apple.iTunes:AUDIOTYPE',  #beatport/traktor specific: track/stem/sample
            'ISRC': '----:com.apple.iTunes:ISRC',
            'PUBLISHEDDATE':
            '----:com.apple.iTunes:PUBLISHEDDATE',  #Beatport release date
            'RELEASEDATE':
            '----:com.apple.iTunes:RELEASEDATE',  #Beatport "street" date
            'UFID': '----:com.apple.iTunes:UFID',  #unique Beatport identifier
            'version':
            '----:com.apple.iTunes:VERSION',  #Version of the Song ("Mix")
            'remixer': '----:com.apple.iTunes:REMIXER',
            'discription': 'desc'
        }

        audiofile = MP4(self.music_file)
        for key in self.metadata.keys():
            if self.overwrite == True or not audiofile[tags[key]]:
                #print(audiofile[tags[key]])
                if tags[key].startswith('----:com.apple.iTunes:'):
                    #use MP4FreeForm method
                    tag = self._convert_to_FreeForm_string(self.metadata[key])
                elif key == 'albumart':
                    albumart = urllib.request.urlopen(self.metadata[key])
                    tag = [
                        MP4Cover(albumart.read(),
                                 imageformat=MP4Cover.FORMAT_JPEG)
                    ]
                    albumart.close()
                else:
                    tag = self.metadata[key]
                audiofile[tags[key]] = tag
            elif self.overwrite == 'merge' and audiofile[tags[key]]:
                if tags[key].startswith('----:com.apple.iTunes:'):
                    #use MP4FreeForm method
                    tag = self._convert_to_FreeForm_string(self.metadata[key])
                elif key == 'albumart':
                    albumart = urllib.request.urlopen(self.metadata[key])
                    tag = [
                        MP4Cover(albumart.read(),
                                 imageformat=MP4Cover.FORMAT_JPEG)
                    ]
                    albumart.close()
                else:
                    tag = self.metadata[key]
                if not isinstance(tag, list):
                    tag = [tag]
                if not isinstance(audiofile[tags[key]], list):
                    audiofile_tag = [audiofile[tags[key]]]
                audiofile[tags[key]] = list(set().union(
                    audiofile[tags[key]], tag))
        audiofile.save()
        return True
Exemple #17
0
def start_process(filenames, mode):
    """
    This is the main funtion of the script
    where it does its main processing.\n
    filenames is the list of files to be processed\n
    mode = 1,2,3 or 4\n
    1 means mp4 to tagged mp4\n
    2 means mp4 with sub to subbed and tagged mp4\n
    3 means mkv to tagged mp4\n
    4 means mkv with sub to subbed and tagged mp4
    """

    searchindex = 0
    for filename in filenames:
        try:
            title = filename[:-4]

            print('\nFetching movie data for "' + title + '"')
            search = tmdb.Search()
            response = search.movie(query=title)
            # getting a Movies object from the id that we got from the search
            # results
            try:  # sometimes blank search results are returned
                tmdb_movie = tmdb.Movies(search.results[searchindex]['id'])
            except IndexError:
                while len(search.results) == 0:
                    title = input("\nCould not find the movie, Enter"
                                  " alternate movie title >> ")

                    searchindex = int(input('Search result index >> '))
                    response = search.movie(query=title)
                    try:
                        tmdb_movie = (tmdb.Movies(
                            search.results[searchindex]['id']))
                    except IndexError:
                        continue
            # we get the info about the movie
            response = tmdb_movie.info()
            # making an imdb object
            imdb = Imdb()
            # tmdb_movie.imdb_id is the imdb id of the moovie that we searched
            # before usng tmdb
            imdb_movie = imdb.get_title_by_id(tmdb_movie.imdb_id)
            # using imdb provided movie name and
            newfilename = (imdb_movie.title + ' (' + str(imdb_movie.year) +
                           ').mp4')
            newfilename = (newfilename.replace(':', ' -').replace('/',
                                                                  ' ').replace(
                                                                      '?', ''))

            command = ""

            if mode == 1:
                # it is required to rename it as its already an mp4 file that
                # wasn't proccessed by ffmpeg
                os.rename(filename, newfilename)
            if mode == 2 or mode == 4:
                command = ('ffmpeg -i "' + filename +
                           '" -sub_charenc UTF-8 -i "' + filename[:-4] +
                           '.srt" ' + '-map 0 -map 1 -c copy -c:s mov_text '
                           '-metadata:s:s:0 handler="English Subtitle" '
                           '-metadata:s:s:0 language=eng '
                           '-metadata:s:a:0 handler="" '
                           '-metadata:s:v:0 handler="" "' + newfilename + '"')
                subprocess.run(command)
            if mode == 3:
                command = ('ffmpeg -i "' + filename +
                           '" -c copy -c:s mov_text '
                           '-metadata:s:s:0 handler="English" '
                           '-metadata:s:s:0 language=eng '
                           '-metadata:s:a:0 handler="" '
                           '-metadata:s:v:0 handler="" '
                           '"' + newfilename + '"')
                subprocess.run(command)

            # the poster is fetched from tmdb only if there is no file
            # named " filename + '.jpg' " in the working directory
            # this way user can provide their own poster image to be used
            poster_filename = filename[:-4] + '.jpg'
            if not os.path.isfile(poster_filename):
                print('\nFetching the movie poster...')
                path = search.results[searchindex]['poster_path']
                poster_path = r'https://image.tmdb.org/t/p/w640' + path

                uo = urllib.request.urlopen(poster_path)
                with open(poster_filename, "wb") as poster_file:
                    poster_file.write(uo.read())
                    poster_file.close()

            imdb_rating_and_plot = str('IMDb rating [' +
                                       str(float(imdb_movie.rating)) +
                                       '/10] - ' + imdb_movie.plot_outline)
            # setting the genres of the movie. I use ';' as a delimeter
            # to searate the multiple genre values
            genre = ';'.join(imdb_movie.genres)
            # Going overboard and adding directors name to artist tag of
            # the mp4 file
            directors = imdb_movie.directors_summary
            director = directors[0].name

            video = MP4(newfilename)
            with open(poster_filename, "rb") as f:
                video["covr"] = [
                    MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG)
                ]
                video['\xa9day'] = str(imdb_movie.year)
                video['\xa9nam'] = imdb_movie.title
                video['\xa9cmt'] = imdb_rating_and_plot
                video['\xa9gen'] = genre
                video['\xa9ART'] = director
                print('\nAdding poster and tagging file...')

            try:
                video.save()
                #  I have encounterd this error in pevious version
                #  of script, now I handle it by removing the metadata
                #  of the file. That seems to solve the probelem
            except OverflowError:
                remove_meta_command = ('ffmpeg -i "' + newfilename +
                                       '" -codec copy -map_metadata -1 "' +
                                       newfilename[:-4] + 'new.mp4"')
                subprocess.run(remove_meta_command)
                video_new = MP4(newfilename[:-4] + 'new.mp4')
                with open(poster_filename, "rb") as f:
                    video_new["covr"] = [
                        MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG)
                    ]
                    video_new['\xa9day'] = str(imdb_movie.year)
                    video_new['\xa9nam'] = imdb_movie.title
                    video_new['\xa9cmt'] = imdb_rating_and_plot
                    video_new['\xa9gen'] = genre
                    video_new['\xa9ART'] = director
                    print('\nAdding poster and tagging file...')

                try:
                    video_new.save()
                    if not os.path.exists('auto fixed files'):
                        os.makedirs('auto fixed files')
                    os.rename(newfilename[:-4] + 'new.mp4',
                              'auto fixed files\\' + newfilename[:-4] + '.mp4')
                    os.remove(newfilename)

                except OverflowError:
                    errored_files.append(filename +
                                         (' - Could not save even after'
                                          'striping metadata'))
                    continue

            os.remove(poster_filename)
            print('\n' + filename +
                  (' was proccesed successfuly!\n\n===================='
                   '======================================'))
        except Exception as e:
            print('\nSome error occured while processing ' + filename +
                  '\n\n====================================================')
            errored_files.append(filename + ' - ' + str(e))
def _add_mp4_image(audio: File, image: Image, image_data):
    image_format = _mp4_formats.get(image.format, MP4Cover.FORMAT_JPEG)
    covr = [MP4Cover(image_data, image_format)]

    audio.tags['covr'] = covr
    audio.save()
Exemple #19
0
def searchITunes(path):

  # list of all m4a files in the input dir
  audioFiles = glob.glob(path + "/*.m4a")

  tracks=[]
  for file in audioFiles:
    # interpret the file as a MP4 file
    tracks.append(MP4(file))

  if len(tracks) == 0:
    return True
  # If the 'covr' metadata is already present then do not overwrite the
  # album art.  In this case we do nothing
  if 'covr' in tracks[0].keys() and len(tracks[0]['covr']) != 0:
    return True

  # Get the album and artists meta data fields
  album = str(tracks[0].tags["\xa9alb"][0])
  artist tracks[0].tags["\xa9ART"][0].encode('utf-8').strip()
  # Some artists metadata contains annoying "featuring" blah
  # In these cases, try to remove the feat part
  # Not 100% robust, there may be weird cases I haven't thought of!
  feat = artist.find(" Feat.")
  if feat >0 :
    artist = artist[:feat]
  searchstr = album + "+" + artist
  # Another list of annoying special chars to replace
  for s in [" ", "&", "'", ",", "."]:
      searchstr=searchstr.replace(s, "+")

  # If there was a double replace, we end up with ++, which is also bad
  tmpStr=searchstr.replace("++", "+")
  while tmpStr != searchstr:
    searchstr = tmpStr
    tmpStr = searchstr.replace("++", "+")

  # This is our final constructed iTunes query
  search=urllib2.urlopen("https://itunes.apple.com/search?term="+searchstr+"&entity=album&media=music&country=GB")
  # The iTunes store search returns a string which is itself a valid
  # python dict.  We want to execute that python to load the dict.
  # First strip the first 3 chars, which are bogus
  result=search.read()[3:]
  # Then construct a string that when executed assigns the dict to albumdata
  result="albumdata="+result

  # Now we can execute the string.  We have to trust Apple here I guess :/
  module = imp.new_module("albumdata")
  exec result in module.__dict__

  albumdata=module.albumdata

  id=0

  # If the resultCount key is smpty then there aren't any valid results. Nothing to do
  if albumdata["resultCount"] == 0:
    print "no iTunes result found for " + searchstr
    return False
  # If there is more than one result, then we want to find the best fit one
  # Simply choose the one with the best match to the album name
  elif albumdata["resultCount"] != 1:
    counter=0
    # 'results' is a list of dicts, which themselves should contain the 'collectionName'
    for result in albumdata['results']:
      # If the 'collectionName' exactly matches the desired album, choose that one
      if result['collectionName'] == album:
        id=counter
        break
      counter += 1

  # Print the artist and album from teh matching results
  print "artist, album = " + albumdata['results'][id]['artistName'] + ", " + albumdata['results'][id]['collectionName']
  # And this is now a url to the album art in the iTunes store.  Request 1080*1080 resolution :)
  imageURL = albumdata['results'][id]['artworkUrl100'].replace("100x100", "1080x1080")

  # Get the image data
  imageFile = urllib2.urlopen(imageURL)
  imageData = imageFile.read()
  # And use mutagen to turn it into an embeddable album art
  cover = MP4Cover(imageData, MP4Cover.FORMAT_JPEG)

  # Loop over all tracks we found at the start and embed the art
  for track in tracks:
    track['covr'] = [cover]
    track.save()

  imageFile.close()

  return True
Exemple #20
0
def Utils_Meta_setMusicInfo(path, info):
    """
    TODO: Write lyrics to file
    :param path:文件目录
    :param info:字典,详情:
    {
        "TALB": "Name of Album",
        "TIT2": "Title",
        "TPE1": "Author,Separate with '/'",
        "APIC": "Path to cover photo",
        "STRICT": Boolean:strict cover mode,
        "TRANSCODE": Boolean:convert to mp3,
        "TRANSPATH": "Path to converted file"
    }
    :return: int {
        0: Nothing need done
        1: Need reExt
    }
    """
    status_code = 0
    try:
        id3 = ID3(path)
        id3.update_to_v23()
        id3.delall("TALB")
        id3.delall("TIT2")
        id3.delall("TPE1")
        id3.delall("APIC")

        id3.add(TALB(encoding=3, text=info["TALB"]))
        id3.add(TIT2(encoding=3, text=info["TIT2"]))
        id3.add(TPE1(encoding=3, text=info["TPE1"]))
        if info["STRICT"]:
            image = Image.open(info["APIC"])
            img_bytes = io.BytesIO()

            if image.size[0] > image.size[1]:
                image = image.crop(
                    (int((image.size[0] - image.size[1]) / 2), 0,
                     int((image.size[0] + image.size[1]) / 2), image.size[1]))
            elif image.size[0] < image.size[1]:
                image = image.crop((0, int(
                    (image.size[1] - image.size[0]) / 2), 0,
                                    int((image.size[0] + image.size[1]) / 2)))
            image.resize((300, 300)).save(img_bytes, format="JPEG")
            id3.add(
                APIC(encoding=0,
                     mime=mimetypes.guess_type(info["APIC"])[0],
                     type=6,
                     data=img_bytes.getvalue()))
        else:
            with open(info["APIC"], "rb") as f:
                id3.add(
                    APIC(encoding=0,
                         mime=mimetypes.guess_type(info["APIC"])[0],
                         type=6,
                         data=f.read()))
        id3.save()
    except ID3NoHeaderError:
        traceback.print_exc()
        ext = os.path.splitext(path)[1]
        if ".flac" in ext or ".FLAC" in ext:
            flac = FLAC(path)
            flac.tags['TITLE'] = info["TIT2"]
            flac.tags['ALBUM'] = info["TALB"]
            flac.tags['ARTIST'] = info["TPE1"]
            with open(info["APIC"], "rb") as f:
                image = Image.open(info["APIC"])
                p = Picture()
                p.data = f.read()
                p.type = 3
                p.mime = mimetypes.guess_type(info["APIC"])[0]
                p.width = image.size[0]
                p.height = image.size[1]
                p.depth = 24  # color depth
                flac.add_picture(p)
                image.close()
            flac.save()
        else:
            try:
                mp4 = MP4(path)
                mp4.tags["\xa9alb"] = info["TALB"]
                mp4.tags["\xa9nam"] = info["TIT2"]
                mp4.tags["\xa9ART"] = info["TPE1"]
                with open(info["APIC"], "rb") as f:
                    mp4["covr"] = [
                        MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_PNG)
                    ]
                mp4.save()
                status_code = 1
            except Exception:
                traceback.print_exc()
        if info["TRANSCODE"]:
            if not os.path.exists(os.path.split(info["TRANSPATH"])[0]):
                os.makedirs(os.path.split(info["TRANSPATH"])[0])
            Utils_FormatTools.Utils_Format_autoTranscode(
                path, info["TRANSPATH"])
            info["TRANSCODE"] = False
            Utils_Meta_setMusicInfo(info["TRANSPATH"], info)
    except MutagenError:
        traceback.print_exc()
    return status_code
Exemple #21
0
def save_song_attrs_to_mp4tags(tags, song):
    # - covr: Artwork
    if song.artwork:
        tags["covr"] = [
            MP4Cover(song.artwork.read(), imageformat=MP4Cover.FORMAT_JPEG)
        ]

    # - \xa9nam: Song Title
    if song.title:
        tags["\xa9nam"] = song.title.decode('unicode-escape')

    # - \xa9ART: Artist
    if song.artist:
        tags["\xa9ART"] = song.artist.decode('unicode-escape')

    # - \xa9day: Year
    if song.year:
        tags["\xa9day"] = str(song.year).decode('unicode-escape')

    # - \xa9alb: Album
    if song.album:
        tags["\xa9alb"] = song.album.decode('unicode-escape')

    # - Release date?
    # release_date =

    # - aART: Album artist
    if song.album_artist:
        tags["aART"] = song.album_artist.decode('unicode-escape')

    # - trkn: Track number
    if song.track_number:
        tags["trkn"] = str(song.track_number).decode('unicode-escape')

    # - tmpo: BPM
    if song.bpm:
        tags["tmpo"] = str(song.bpm).decode('unicode-escape')

    # - Original artist
    # if song.original_artist:
    #    ???

    # - Key
    # if song.key:
    #    ???

    # - \xa9wrt: Composer
    if song.composer:
        tags["\xa9wrt"] = song.composer.decode('unicode-escape')

    # - \xa9lyr: Lyricist
    if song.lyrics:
        tags["\xa9lyr"] = song.lyrics.decode('unicode-escape')

    # - \xa9cmt: Comments
    if song.comments:
        tags["\xa9cmt"] = song.comments.decode('unicode-escape')

    # - Remixer
    # if song.remixer:
    #    ???

    # - Label/Publisher
    # if song.label:
    #    ???

    # - \xa9gen: Genre/content type
    if song.genre:
        tags["\xa9gen"] = song.genre.decode('unicode-escape')
Exemple #22
0
    def run(self, info):
        filename = info['filepath']
        temp_filename = prepend_extension(filename, 'temp')

        if not info.get('thumbnails'):
            self.to_screen('There aren\'t any thumbnails to embed')
            return [], info

        idx = next((-i for i, t in enumerate(info['thumbnails'][::-1], 1)
                    if t.get('filepath')), None)
        if idx is None:
            self.to_screen('There are no thumbnails on disk')
            return [], info
        thumbnail_filename = info['thumbnails'][idx]['filepath']
        if not os.path.exists(encodeFilename(thumbnail_filename)):
            self.report_warning(
                'Skipping embedding the thumbnail because the file is missing.'
            )
            return [], info

        # Correct extension for WebP file with wrong extension (see #25687, #25717)
        convertor = FFmpegThumbnailsConvertorPP(self._downloader)
        convertor.fixup_webp(info, idx)

        original_thumbnail = thumbnail_filename = info['thumbnails'][idx][
            'filepath']

        # Convert unsupported thumbnail formats to PNG (see #25687, #25717)
        # Original behavior was to convert to JPG, but since JPG is a lossy
        # format, there will be some additional data loss.
        # PNG, on the other hand, is lossless.
        thumbnail_ext = os.path.splitext(thumbnail_filename)[1][1:]
        if thumbnail_ext not in ('jpg', 'jpeg', 'png'):
            thumbnail_filename = convertor.convert_thumbnail(
                thumbnail_filename, 'png')
            thumbnail_ext = 'png'

        mtime = os.stat(encodeFilename(filename)).st_mtime

        success = True
        if info['ext'] == 'mp3':
            options = [
                '-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version',
                '3', '-metadata:s:v', 'title="Album cover"', '-metadata:s:v',
                'comment="Cover (front)"'
            ]

            self._report_run('ffmpeg', filename)
            self.run_ffmpeg_multiple_files([filename, thumbnail_filename],
                                           temp_filename, options)

        elif info['ext'] in ['mkv', 'mka']:
            options = ['-c', 'copy', '-map', '0', '-dn']

            mimetype = 'image/%s' % ('png'
                                     if thumbnail_ext == 'png' else 'jpeg')
            old_stream, new_stream = self.get_stream_number(
                filename, ('tags', 'mimetype'), mimetype)
            if old_stream is not None:
                options.extend(['-map', '-0:%d' % old_stream])
                new_stream -= 1
            options.extend([
                '-attach', thumbnail_filename,
                '-metadata:s:%d' % new_stream,
                'mimetype=%s' % mimetype,
                '-metadata:s:%d' % new_stream,
                'filename=cover.%s' % thumbnail_ext
            ])

            self._report_run('ffmpeg', filename)
            self.run_ffmpeg(filename, temp_filename, options)

        elif info['ext'] in ['m4a', 'mp4', 'mov']:
            prefer_atomicparsley = 'embed-thumbnail-atomicparsley' in self.get_param(
                'compat_opts', [])
            # Method 1: Use mutagen
            if not has_mutagen or prefer_atomicparsley:
                success = False
            else:
                try:
                    self._report_run('mutagen', filename)
                    meta = MP4(filename)
                    # NOTE: the 'covr' atom is a non-standard MPEG-4 atom,
                    # Apple iTunes 'M4A' files include the 'moov.udta.meta.ilst' atom.
                    f = {
                        'jpeg': MP4Cover.FORMAT_JPEG,
                        'png': MP4Cover.FORMAT_PNG
                    }[imghdr.what(thumbnail_filename)]
                    with open(thumbnail_filename, 'rb') as thumbfile:
                        thumb_data = thumbfile.read()
                    meta.tags['covr'] = [
                        MP4Cover(data=thumb_data, imageformat=f)
                    ]
                    meta.save()
                    temp_filename = filename
                except Exception as err:
                    self.report_warning('unable to embed using mutagen; %s' %
                                        error_to_compat_str(err))
                    success = False

            # Method 2: Use ffmpeg+ffprobe
            if not success and not prefer_atomicparsley:
                success = True
                try:
                    options = ['-c', 'copy', '-map', '0', '-dn', '-map', '1']

                    old_stream, new_stream = self.get_stream_number(
                        filename, ('disposition', 'attached_pic'), 1)
                    if old_stream is not None:
                        options.extend(['-map', '-0:%d' % old_stream])
                        new_stream -= 1
                    options.extend(
                        ['-disposition:%s' % new_stream, 'attached_pic'])

                    self._report_run('ffmpeg', filename)
                    self.run_ffmpeg_multiple_files(
                        [filename, thumbnail_filename], temp_filename, options)
                except PostProcessingError as err:
                    self.report_warning(
                        'unable to embed using ffprobe & ffmpeg; %s' %
                        error_to_compat_str(err))
                    success = False

            # Method 3: Use AtomicParsley
            if not success:
                success = True
                atomicparsley = next(
                    (x for x in ['AtomicParsley', 'atomicparsley']
                     if check_executable(x, ['-v'])), None)
                if atomicparsley is None:
                    raise EmbedThumbnailPPError(
                        'AtomicParsley was not found. Please install')

                cmd = [
                    encodeFilename(atomicparsley, True),
                    encodeFilename(filename, True),
                    encodeArgument('--artwork'),
                    encodeFilename(thumbnail_filename, True),
                    encodeArgument('-o'),
                    encodeFilename(temp_filename, True)
                ]
                cmd += [
                    encodeArgument(o)
                    for o in self._configuration_args('AtomicParsley')
                ]

                self._report_run('atomicparsley', filename)
                self.write_debug('AtomicParsley command line: %s' %
                                 shell_quote(cmd))
                p = subprocess.Popen(cmd,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
                stdout, stderr = process_communicate_or_kill(p)
                if p.returncode != 0:
                    msg = stderr.decode('utf-8', 'replace').strip()
                    raise EmbedThumbnailPPError(msg)
                # for formats that don't support thumbnails (like 3gp) AtomicParsley
                # won't create to the temporary file
                if b'No changes' in stdout:
                    self.report_warning(
                        'The file format doesn\'t support embedding a thumbnail'
                    )
                    success = False

        elif info['ext'] in ['ogg', 'opus', 'flac']:
            if not has_mutagen:
                raise EmbedThumbnailPPError(
                    'module mutagen was not found. Please install using `python -m pip install mutagen`'
                )

            self._report_run('mutagen', filename)
            f = {
                'opus': OggOpus,
                'flac': FLAC,
                'ogg': OggVorbis
            }[info['ext']](filename)

            pic = Picture()
            pic.mime = 'image/%s' % imghdr.what(thumbnail_filename)
            with open(thumbnail_filename, 'rb') as thumbfile:
                pic.data = thumbfile.read()
            pic.type = 3  # front cover
            res = self._get_thumbnail_resolution(thumbnail_filename,
                                                 info['thumbnails'][idx])
            if res is not None:
                pic.width, pic.height = res

            if info['ext'] == 'flac':
                f.add_picture(pic)
            else:
                # https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
                f['METADATA_BLOCK_PICTURE'] = base64.b64encode(
                    pic.write()).decode('ascii')
            f.save()
            temp_filename = filename

        else:
            raise EmbedThumbnailPPError(
                'Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov'
            )

        if success and temp_filename != filename:
            os.remove(encodeFilename(filename))
            os.rename(encodeFilename(temp_filename), encodeFilename(filename))

        self.try_utime(filename, mtime, mtime)

        files_to_delete = [thumbnail_filename]
        if self._already_have_thumbnail:
            if original_thumbnail == thumbnail_filename:
                files_to_delete = []
        elif original_thumbnail != thumbnail_filename:
            files_to_delete.append(original_thumbnail)
        return files_to_delete, info
Exemple #23
0
    def writeTags(self, mp4Path, artwork=True, thumbnail=False):
        self.log.info("Tagging file: %s." % mp4Path)
        ext = os.path.splitext(mp4Path)[1][1:]
        if ext not in valid_tagging_extensions:
            self.log.error("File is not the correct format.")
            return False

        video = MP4(mp4Path)
        checktags = {}
        checktags["\xa9nam"] = self.title  # Movie title
        checktags["desc"] = self.shortdescription  # Short description
        checktags["ldes"] = self.description  # Long description
        checktags["\xa9day"] = self.date  # Year
        #checktags["stik"] = [9]  # Movie iTunes category
         
        #if self.HD is not None:
        #    checktags["hdvd"] = self.HD
        if self.genre is not None:
            genre = None
            for g in self.genre:
                if genre is None:
                    genre = g['name']
                    break
                # else:
                    # genre += ", " + g['name']
            checktags["\xa9gen"] = genre  # Genre(s)
        #checktags["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode("UTF-8", errors="ignore")  # XML - see xmlTags method
        '''
        rating = self.rating()
        if rating is not None:
            checktags["----:com.apple.iTunes:iTunEXTC"] = rating
        '''

        if artwork:
            path = self.getArtwork(mp4Path)
            if path is not None:
                cover = open(path, 'rb').read()
                if path.endswith('png'):
                    checktags["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)]  # png poster
                else:
                    checktags["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)]  # jpeg poster
        
        ProcessTags = False
        for keys, values in checktags.items():
            if video.tags == None:
                ProcessTags = True
                break
            elif keys in video.tags:
                if video.tags[keys] != [values]:
                    self.log.info(keys + " tag does not match and will be updated")
                    ProcessTags = True
                    break
            else:
                self.log.debug(keys + " will be added")
                ProcessTags = True
        if not ProcessTags:
            self.log.info("All MP4 tags match the original, skipping tagging.")
        else:
            try:
                video.delete()
            except IOError:
                self.log.debug("Unable to clear original tags, attempting to proceed.")

            video["\xa9nam"] = self.title  # Movie title
            video["desc"] = self.shortdescription  # Short description
            video["ldes"] = self.description  # Long description
            video["\xa9day"] = self.date  # Year
            #video["stik"] = [9]  # Movie iTunes category
            #if self.HD is not None:
            #    video["hdvd"] = self.HD
            if self.genre is not None:
                genre = None
                for g in self.genre:
                    if genre is None:
                        genre = g['name']
                        break
                    # else:
                        # genre += ", " + g['name']
                video["\xa9gen"] = genre  # Genre(s)
            #video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode("UTF-8", errors="ignore")  # XML - see xmlTags method

            '''
            rating = self.rating()
            if rating is not None:
                video["----:com.apple.iTunes:iTunEXTC"] = rating
            '''

            if artwork:
                path = self.getArtwork(mp4Path)
                if path is not None:
                    cover = open(path, 'rb').read()
                    if path.endswith('png'):
                        video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)]  # png poster
                    else:
                        video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)]  # jpeg poster
            if self.original:
                video["\xa9too"] = "MDH:" + os.path.basename(self.original)
            else:
                video["\xa9too"] = "MDH:" + os.path.basename(mp4Path)

            for i in range(3):
                try:
                    self.log.info("Trying to write tags.")
                    video.save()
                    self.log.info("Tags written successfully.")
                    return True
                except IOError as e:
                    self.log.info("Exception: %s" % e)
                    self.log.exception("There was a problem writing the tags. Retrying.")
                    time.sleep(5)
            return False
Exemple #24
0
    def writeTags(self, path, converter, artwork=True, thumbnail=False, width=None, height=None, streaming=0):
        self.log.info("Tagging file: %s." % path)
        if width and height:
            try:
                self.setHD(width, height)
            except:
                self.log.exception("Unable to set HD tag.")

        try:
            video = MP4(path)
        except (MP4StreamInfoError, KeyError):
            self.log.debug('File is not a valid MP4 file and cannot be tagged using mutagen, falling back to FFMPEG limited tagging.')
            try:
                metadata = {}
                if self.mediatype == MediaType.Movie:
                    metadata['TITLE'] = self.title  # Movie title
                    metadata["COMMENT"] = self.description  # Long description
                    metadata["DATE_RELEASE"] = self.date  # Year
                    metadata["DATE"] = self.date  # Year
                elif self.mediatype == MediaType.TV:
                    metadata['TITLE'] = self.title  # Video title
                    metadata["COMMENT"] = self.description  # Long description
                    metadata["DATE_RELEASE"] = self.date  # Air Date
                    metadata["DATE"] = self.date  # Air Date
                    metadata["ALBUM"] = self.showname + ", Season " + str(self.season)  # Album as Season

                if self.genre and len(self.genre) > 0:
                    metadata["GENRE"] = self.genre[0].get('name')

                metadata["ENCODER"] = "SMA"

                coverpath = None
                if artwork:
                    coverpath = self.getArtwork(path, thumbnail=thumbnail)

                try:
                    conv = converter.tag(path, metadata, coverpath, streaming)
                except KeyboardInterrupt:
                    raise
                except:
                    self.log.exception("FFMPEG Tag Error.")
                    return False
                _, cmds = next(conv)
                self.log.debug("Metadata tagging FFmpeg command:")
                self.log.debug(" ".join(str(item) for item in cmds))
                for timecode, debug in conv:
                    self.log.debug(debug)
                self.log.info("Tags written successfully using FFMPEG fallback method.")
                return True
            except KeyboardInterrupt:
                raise
            except:
                self.log.exception("Unexpected tagging error using FFMPEG fallback method.")
                return False

        try:
            video.delete()
        except KeyboardInterrupt:
            raise
        except:
            self.log.debug("Unable to clear original tags, will proceed.")

        if self.mediatype == MediaType.Movie:
            video["\xa9nam"] = self.title  # Movie title
            video["desc"] = self.tagline  # Short description
            video["ldes"] = self.description  # Long description
            video["\xa9day"] = self.date  # Year
            video["stik"] = [9]  # Movie iTunes category
        elif self.mediatype == MediaType.TV:
            video["tvsh"] = self.showname  # TV show title
            video["\xa9nam"] = self.title  # Video title
            video["tven"] = self.title  # Episode title
            video["desc"] = self.shortDescription  # Short description
            video["ldes"] = self.description  # Long description
            network = [x['name'] for x in self.network]
            video["tvnn"] = network  # Network
            video["\xa9day"] = self.date  # Air Date
            video["tvsn"] = [self.season]  # Season number
            video["disk"] = [(self.season, 0)]  # Season number as disk
            video["\xa9alb"] = self.showname + ", Season " + str(self.season)  # iTunes Album as Season
            video["tves"] = [self.episode]  # Episode number
            video["trkn"] = [(self.episode, len(self.seasondata.get('episodes', [])))]  # Episode number iTunes
            video["stik"] = [10]  # TV show iTunes category

        if self.HD:
            video["hdvd"] = self.HD
        if self.genre and len(self.genre) > 0:
            video["\xa9gen"] = self.genre[0].get('name')
        video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode("UTF-8", errors="ignore")  # XML - see xmlTags method
        if self.rating:
            video["----:com.apple.iTunes:iTunEXTC"] = self.rating.encode("UTF-8", errors="ignore")  # iTunes content rating

        if artwork:
            coverpath = self.getArtwork(path, thumbnail=thumbnail)
            if coverpath is not None:
                cover = open(coverpath, 'rb').read()
                if coverpath.endswith('png'):
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)]  # png poster
                else:
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)]  # jpeg poster

        if self.original:
            video["\xa9too"] = "SMA:" + os.path.basename(self.original)
        else:
            video["\xa9too"] = "SMA:" + os.path.basename(path)

        try:
            self.log.info("Trying to write tags.")
            video.save()
            self.log.info("Tags written successfully using mutagen.")
            return True
        except KeyboardInterrupt:
            raise
        except:
            self.log.exception("There was an error writing the tags.")
        return False
Exemple #25
0
    def writeTags(self, mp4Path, artwork=True):
        self.log.info("Tagging file: %s." % mp4Path)
        ext = os.path.splitext(mp4Path)[1][1:]
        if ext not in valid_output_extensions:
            self.log.error("File is not the correct format.")
            sys.exit()
        try:
            MP4(mp4Path).delete()
        except IOError:
            self.log.debug(
                "Unable to clear original tags, attempting to proceed.")

        video = MP4(mp4Path)
        video["tvsh"] = self.show  # TV show title
        video["\xa9nam"] = self.title  # Video title
        video["tven"] = self.title  # Episode title
        video["desc"] = self.shortDescription()  # Short description
        video[
            "ldes"] = self.description  # Long description (same a short for tv)
        video["tvnn"] = self.network  # Network
        if self.airdate != "0000-00-00":
            video["\xa9day"] = self.airdate  # Airdate
        video["tvsn"] = [self.season]  # Season number
        video["disk"] = [(int(self.season), 0)]  # Season number as disk
        video["\xa9alb"] = self.show + ", Season " + str(
            self.season)  # iTunes Album as Season
        video["tves"] = [self.episode]  # Episode number
        video["trkn"] = [(int(self.episode), len(self.seasondata))
                         ]  # Episode number iTunes
        video["stik"] = [10]  # TV show iTunes category
        if self.HD is not None:
            video["hdvd"] = self.HD
        if self.genre is not None:
            video["\xa9gen"] = self.genre[1:-1].split('|')[0]
            #video["\xa9gen"] = self.genre.replace('|', ',')[1:-1]  # Genre(s)
        video[
            "----:com.apple.iTunes:iTunMOVI"] = self.xml  # XML - see xmlTags method
        video["----:com.apple.iTunes:iTunEXTC"] = self.setRating(
        )  # iTunes content rating

        if artwork:
            path = self.getArtwork(mp4Path)
            if path is not None:
                cover = open(path, 'rb').read()
                if path.endswith('png'):
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG)
                                     ]  # png poster
                else:
                    video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)
                                     ]  # jpeg poster
        if self.original:
            video["\xa9too"] = "MDH:" + os.path.basename(self.original)
        else:
            video["\xa9too"] = "MDH:" + os.path.basename(mp4Path)
        MP4(mp4Path).delete(mp4Path)
        for i in range(3):
            try:
                self.log.info("Trying to write tags.")
                video.save()
                self.log.info("Tags written successfully.")
                break
            except IOError as e:
                self.log.exception(
                    "There was a problem writing the tags. Retrying.")
                time.sleep(5)
def processFilm(film_id, filepath):
    global subtitlesActioned
    subtitlesFound = subtitlesExistForItem(filepath)
    fileExtPattern = re.compile('\.[a-zA-Z0-9]+$')
    oldfilePath = filepath
    ext = fileExtPattern.findall(filepath)[0]
    newfilepath = filepath.replace(ext, '-with-subs' + ext)
    print("\n\n========\n\n")
    print(filepath)
    print(newfilepath)
    print(oldfilePath)
    if subtitlesFound and subtitlesActioned == False:
        subtitlesActioned = True
        print("\n\n\nCALLING " + " ".join([
            'ffmpeg', '-i', oldfilePath, '-i', subtitlesFound, '-c:s mov_text',
            newfilepath
        ]))
        print("\n\n\n\n")
        subprocess.call([
            'ffmpeg', '-i', oldfilePath, '-i', subtitlesFound, '-c:s mov_text',
            newfilepath
        ])
    filetags = checkTags(filepath)
    if subtitlesActioned:
        # tagged_file = MP4(newfilepath)
        print("true")
    else:
        tagged_file = MP4(oldfilePath)
    print(tagged_file.tags)
    data = getFilmData(film_id)
    tagged_file['stik'] = [9]
    genres = []

    if 'genres' in data:
        for genre in data['genres']:
            genres.append(genre['name'])
        tagged_file['\xa9gen'] = genres
    if 'overview' in data:
        tagged_file['ldes'] = data['overview']
        tagged_file['desc'] = data['overview']
    if 'title' in data:
        tagged_file['\xa9alb'] = data['title']
        tagged_file['aART'] = data['title']
        tagged_file['\xa9nam'] = data['title']
    elif 'original_title' in data:
        tagged_file['\xa9alb'] = data['original_title']
        tagged_file['aART'] = data['original_title']
        tagged_file['\xa9nam'] = data['original_title']
    if 'poster_path' in data:
        with open(data['poster_path'][1:], "rb") as f:
            tagged_file["covr"] = [
                MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG)
            ]
    if 'release_date' in data:
        tagged_file['\xa9day'] = data['release_date'][:4]

    # GET CAST AND CREW

    cast_crew_data = getCastandCrew(film_id, "movie")
    cast = []
    directors = []
    screenwriters = []
    producers = []
    producer_re = re.compile("Producer$")
    for cast_member in cast_crew_data['cast']:
        cast.append(cast_member['name'])

    for crew_members in cast_crew_data['crew']:
        if crew_members['job'] == "Director":
            directors.append(crew_members['name'])
        if crew_members['department'] == "Writing":
            screenwriters.append(crew_members['name'])
        if producer_re.search(crew_members['job']):
            producers.append(crew_members['name'])

    xml_str = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
    xml_str += "<plist version=\"1.0\">\n"
    xml_str += "<dict>"
    xml_str += generateXML(cast, "cast")
    xml_str += generateXML(directors, "directors")
    xml_str += generateXML(screenwriters, "screenwriters")
    xml_str += generateXML(producers, "producers")
    xml_str += "</dict>"
    xml_str += "</plist>"

    tagged_file['----:com.apple.iTunes:iTunMOVI'] = str.encode(xml_str)
    # hdvd
    # 0 - nothing
    # 1 - 720p
    # 2 - 1080p
    # 3 - 4K

    vid = cv2.VideoCapture(filepath)
    height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
    width = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
    print(width)

    if width > 1919 and width < 3839:
        tagged_file['hdvd'] = [2]
    elif width < 1919 and width > 1279:
        tagged_file['hdvd'] = [1]
    elif width > 3839:
        tagged_file['hdvd'] = [3]
    else:
        tagged_file['hdvd'] = [0]

    # GENERATE XML AND AS AS BITES TO ----:com.apple.iTunes:iTunMOVI TAG
    rating = getClassification(film_id)
    tagged_file['----:com.apple.iTunes:iTunEXTC'] = str.encode("b'mpaa|" +
                                                               rating +
                                                               "|300|")

    tagged_file.save()
Exemple #27
0
 def test_cover_png(self):
     self.set_key('covr', [
         MP4Cover(b'woooo', MP4Cover.FORMAT_PNG),
         MP4Cover(b'hoooo', MP4Cover.FORMAT_JPEG),
     ])
def applyData(data, filepath, show_id, filename):
    global season_artwork, season_data, show_data
    print(data)
    tagged_file = MP4(filepath)
    tagged_file['stik'] = [10]
    if 'season_number' in data:
        tagged_file['tvsn'] = [data['season_number']]
    if 'episode_number' in data:
        tagged_file['tves'] = [data['episode_number']]
    if season_artwork != "":
        with open(season_artwork, "rb") as f:
            tagged_file["covr"] = [
                MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG)
            ]
    if 'air_date' in data:
        tagged_file['\xa9day'] = data['air_date'][:4]
    if 'name' in data:
        tagged_file['\xa9nam'] = data['name']
    if 'overview' in data:
        tagged_file['desc'] = data['overview']
    if 'original_name' in show_data:
        tagged_file['tvsh'] = show_data['original_name']
        tagged_file['\xa9alb'] = show_data['original_name']
        tagged_file['\xa9ART'] = show_data['original_name']
        tagged_file['aART'] = show_data['original_name']
    vid = cv2.VideoCapture(filepath)
    height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
    width = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
    print(width)

    if width > 1919 and width < 3839:
        tagged_file['hdvd'] = [2]
    elif width < 1919 and width > 1279:
        tagged_file['hdvd'] = [1]
    elif width > 3839:
        tagged_file['hdvd'] = [3]
    else:
        tagged_file['hdvd'] = [0]

    cast_crew_data = getCastandCrew(show_id, "tv")
    cast = []
    directors = []
    screenwriters = []
    producers = []
    producer_re = re.compile("Producer$")
    for cast_member in cast_crew_data['cast']:
        cast.append(cast_member['name'])

    for crew_members in cast_crew_data['crew']:
        if crew_members['job'] == "Director":
            directors.append(crew_members['name'])
        if crew_members['department'] == "Writing":
            screenwriters.append(crew_members['name'])
        if producer_re.search(crew_members['job']):
            producers.append(crew_members['name'])

    xml_str = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
    xml_str += "<plist version=\"1.0\">\n"
    xml_str += "<dict>"
    xml_str += generateXML(cast, "cast")
    xml_str += generateXML(directors, "directors")
    xml_str += generateXML(screenwriters, "screenwriters")
    xml_str += generateXML(producers, "producers")
    xml_str += "</dict>"
    xml_str += "</plist>"

    tagged_file['----:com.apple.iTunes:iTunMOVI'] = str.encode(xml_str)

    rating = getTVContentRating(show_id)
    tagged_file['----:com.apple.iTunes:iTunEXTC'] = str.encode("b'mpaa|" +
                                                               rating +
                                                               "|300|")

    genres = []

    if 'genres' in show_data:
        for genre in show_data['genres']:
            genres.append(genre['name'])
        tagged_file['\xa9gen'] = genres

    tagged_file.save()
Exemple #29
0
 def test_cmp_bytes(self):
     self.assertReallyEqual(MP4Cover(b'woooo'), b"woooo")
     self.assertReallyNotEqual(MP4Cover(b'woooo'), b"foo")
Exemple #30
0
  def write_metadata(self, filename, force=False):

    # MP4 needs these attributes as TXXX.
    for value in ('original album', 'original_artist', 'original_year'):
      self.txxx[value.upper().replace('_', ' ')] = value

    track = self.track

    log.debug("Writing metadata for: %s", filename)

    if os.path.exists(filename) is False:
      log.warn("Couldn't find MP4 file!: %s", filename)
      return None

    self.tags = mutagen.mp4.MP4(filename)

    if not force and self.is_up_to_date():
      log.debug('Up to date: "%s"' % filename)
      return None

    # Clear out any old data.
    self.tags.clear()

    # Basics first.
    for atom, key in self.attributes.items():

      if hasattr(track, key):
        value = getattr(track, key, None)

        log.debug("Trying: key: %s (%s)", key, value)

        if isinstance(value, str):
          value = value.encode('utf-8')

        # 'tmpo' needs to be a list of integers.
        if key == 'bpm' and value is not None:
          value = [int(value)]

        if value is not None:
          self.tags[atom] = value

    # Hack alert.. not sure how better to "detect" this.
    if track.genre:
      for genre in list(track.genre):
        if genre in self.gapless:
          self.tags["pgap"] = True

    if track.compilation:
      self.tags["cpil"] = True

    if track.tracknumber and track.tracktotal:
      self.tags["trkn"] = [(track.tracknumber, track.tracktotal)]

    elif track.tracknumber:
      self.tags["trkn"] = [(track.tracknumber, 0)]

    # Convert RG tags into iTunes SoundCheck
    # TODO: Find what tags aacgain uses as well.
    if track.replaygain_album_gain:
      self.tags['----:com.apple.iTunes:iTunNORM'] = replay_gain_to_soundcheck(track.replaygain_album_gain, track.replaygain_album_peak)

    elif track.replaygain_track_gain:
      self.tags['----:com.apple.iTunes:iTunNORM'] = replay_gain_to_soundcheck(track.replaygain_track_gain, track.replaygain_track_peak)

    #
    if track.discnumber and track.disctotal:
      try:
        self.tags["disk"] = [(track.discnumber, track.disctotal)]
      except ValueError:
        pass

    elif track.disctotal:
      self.tags["disk"] = [(track.disctotal, track.disctotal)]

    # Artwork time..
    if track.cover_file and os.path.exists(track.cover_file):

      with open(track.cover_file, 'rb') as fh:

        if track.cover_file.endswith(".png"):
          self.tags["covr"] = [ MP4Cover(fh.read(), MP4Cover.FORMAT_PNG) ]
        elif track.cover_file.endswith(".jpg"):
          self.tags["covr"] = [ MP4Cover(fh.read(), MP4Cover.FORMAT_JPEG) ]

    # Always add the check & time stamp for next time.
    if track.checksum:
      self.tags['----:com.sully.flac2mp4:checksum'] = str(track.checksum)

    self.tags['----:com.sully.flac2mp4:flacmtime'] = str(track.mtime)

    # Convert all user defined tags.
    for tag, attribute in self.txxx.items():

      if getattr(track, attribute, None):
        self.tags['----:com.apple.iTunes:' + tag] = getattr(track, attribute).encode('utf-8')

    try:
      self.tags.save(filename)
    except Exception as e:
      log.warn("Couldn't save file %s: %s", filename, e)